This commit is contained in:
jona605a
2020-08-06 17:22:33 +02:00
42 changed files with 1239 additions and 1842 deletions

View File

@ -1,10 +1,10 @@
"""A collection of all Gwendolyn functions."""
__all__ = ["helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToNumber", "fiarReactionTest", "deleteGame", "stopServer", "checkBalance", "giveMoney", "addMoney", "triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "parseChar", "parseRoll", "critRoll", "parseDestiny", "parseHex", "hexAI", "addToDict", "getName", "getID"]
__all__ = ["helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToCommand", "fiarReactionTest", "deleteGame", "stopServer", "checkBalance", "giveMoney", "addMoney", "triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "parseChar", "parseRoll", "critRoll", "parseDestiny", "parseHex", "addToDict", "getName", "getID", "replaceMultiple", "hexAI", "parseMonopoly", "monopolyContinue", "monopolyReactionTest"]
from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToNumber, fiarReactionTest, deleteGame, stopServer, addToDict, getName, getID
from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToCommand, fiarReactionTest, deleteGame, stopServer, addToDict, getName, getID, monopolyReactionTest
from .games import checkBalance, giveMoney, addMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, parseHex, hexAI
from .games import checkBalance, giveMoney, addMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, parseHex, hexAI, parseMonopoly, monopolyContinue
from .lookup import spellFunc, monsterFunc
@ -13,4 +13,3 @@ from .other import nameGen, tavernGen, movieFunc
from .roll import roll_dice
from .swfuncs import parseChar, parseRoll, parseDestiny, critRoll

View File

@ -1,9 +1,10 @@
"""Functions for games Gwendolyn can play."""
__all__ = ["checkBalance", "giveMoney", "addMoney","triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "parseHex","hexAI"]
__all__ = ["checkBalance", "giveMoney", "addMoney","triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "parseHex", "hexAI", "parseMonopoly", "monopolyContinue"]
from .money import checkBalance, giveMoney, addMoney
from .trivia import triviaCountPoints, triviaStart, triviaAnswer
from .blackjack import blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit
from .fourInARow import parseFourInARow, fourInARowAI
from .hex import parseHex, hexAI
from .monopoly import parseMonopoly, monopolyContinue

View File

@ -197,126 +197,18 @@ def blackjackHit(channel,user,handNumber = 0):
data = json.load(f)
if user in data["blackjack games"][channel]["user hands"]:
if data["blackjack games"][channel]["user hands"][user]["split"] == 0:
hand = data["blackjack games"][channel]["user hands"][user]
handNumber = 0
else:
if handNumber != 0:
if handNumber == 1:
hand = data["blackjack games"][channel]["user hands"][user]
elif handNumber == 2:
hand = data["blackjack games"][channel]["user hands"][user]["other hand"]
elif handNumber == 3:
hand = data["blackjack games"][channel]["user hands"][user]["third hand"]
elif handNumber == 4:
hand = data["blackjack games"][channel]["user hands"][user]["fourth hand"]
else:
logThis(user+" tried to hit without specifying which hand")
return "You have to specify the hand you're hitting with."
else:
logThis(user+" tried to hit without specifying which hand")
return "You have to specify the hand you're hitting with."
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
hand["hand"].append(drawCard(channel))
hand["hit"] = True
handValue = calcHandValue(hand["hand"])
if handValue > 21:
hand["busted"] = True
if handNumber == 2:
data["blackjack games"][channel]["user hands"][user]["other hand"] = hand
elif handNumber == 3:
data["blackjack games"][channel]["user hands"][user]["third hand"] = hand
elif handNumber == 4:
data["blackjack games"][channel]["user hands"][user]["fourth hand"] = hand
else:
data["blackjack games"][channel]["user hands"][user] = hand
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
response = "accept"
roundDone = True
for person in data["blackjack games"][channel]["user hands"].values():
if person["hit"] == False and person["standing"] == False:
roundDone = False
if person["split"] > 0:
if person["other hand"]["hit"] == False and person["other hand"]["standing"] == False:
roundDone = False
if person["split"] > 1:
if person["third hand"]["hit"] == False and person["third hand"]["standing"] == False:
roundDone = False
if person["split"] > 2:
if person["fourth hand"]["hit"] == False and person["fourth hand"]["standing"] == False:
roundDone = False
return response + str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
else:
logThis(user+" is already standing")
return "You can't hit when you're standing"
else:
logThis(user+" has already hit this round")
return "You've already hit this round"
else:
logThis(user+" tried to hit on the 0th round")
return "You can't hit before you see your cards"
else:
logThis(user+" tried to hit without being in the game")
return "You have to enter the game before you can hit"
# When players try to double down
def blackjackDouble(channel,user,handNumber = 0):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if data["blackjack games"][channel]["user hands"][user]["split"] == 0:
hand = data["blackjack games"][channel]["user hands"][user]
handNumber = 0
else:
if handNumber != 0:
if handNumber == 1:
hand = data["blackjack games"][channel]["user hands"][user]
elif handNumber == 2:
hand = data["blackjack games"][channel]["user hands"][user]["other hand"]
elif handNumber == 3:
hand = data["blackjack games"][channel]["user hands"][user]["third hand"]
elif handNumber == 4:
hand = data["blackjack games"][channel]["user hands"][user]["fourth hand"]
else:
logThis(user+" tried to double without specifying which hand")
return "You have to specify the hand you're doubling down.",""
else:
logThis(user+" tried to double without specifying which hand")
return "You have to specify the hand you're doubling down.",""
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
if len(hand["hand"]) == 2:
bet = hand["bet"]
if money.checkBalance(user) >= bet:
money.addMoney(user,-1 * bet)
with open("resources/games/games.json", "r") as f:
data = json.load(f)
hand, handNumber = getHandNumber(data["blackjack games"][channel]["user hands"][user],handNumber)
print(hand)
if hand != None:
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
hand["hand"].append(drawCard(channel))
hand["hit"] = True
hand["doubled"] = True
hand["bet"] += bet
handValue = calcHandValue(hand["hand"])
if handValue > 21:
hand["busted"] = True
@ -333,41 +225,93 @@ def blackjackDouble(channel,user,handNumber = 0):
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
roundDone = True
response = "accept"
roundDone = isRoundDone(data["blackjack games"][channel])
for person in data["blackjack games"][channel]["user hands"].values():
if person["hit"] == False and person["standing"] == False:
roundDone = False
if person["split"] > 0:
if person["other hand"]["hit"] == False and person["other hand"]["standing"] == False:
roundDone = False
if person["split"] > 1:
if person["third hand"]["hit"] == False and person["third hand"]["standing"] == False:
roundDone = False
if person["split"] > 2:
if person["fourth hand"]["hit"] == False and person["fourth hand"]["standing"] == False:
roundDone = False
return "Adding another "+str(bet)+" GwendoBucks to "+getName(user)+"'s bet and drawing another card.",str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
return response + str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
else:
logThis(user+" doesn't have enough GwendoBucks")
return "You don't have enough GwendoBucks",""
logThis(user+" is already standing")
return "You can't hit when you're standing"
else:
logThis(user+" tried to double on round "+str(data["blackjack games"][channel]["round"]))
return "You can only double down on the first round",""
logThis(user+" has already hit this round")
return "You've already hit this round"
else:
logThis(user+" is already standing")
return "You can't double when you're standing",""
logThis(user+" tried to hit on the 0th round")
return "You can't hit before you see your cards"
else:
logThis(user+" has already hit this round")
return "You've already hit this round",""
logThis(user+" didn't specify a hand")
return "You need to specify a hand"
else:
logThis(user+" tried to double on the 0th round")
return "You can't double down before you see your cards",""
logThis(user+" tried to hit without being in the game")
return "You have to enter the game before you can hit"
# When players try to double down
def blackjackDouble(channel,user,handNumber = 0):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if user in data["blackjack games"][channel]["user hands"]:
hand, handNumber = getHandNumber(data["blackjack games"][channel]["user hands"][user],handNumber)
if hand != None:
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
if len(hand["hand"]) == 2:
bet = hand["bet"]
if money.checkBalance(user) >= bet:
money.addMoney(user,-1 * bet)
with open("resources/games/games.json", "r") as f:
data = json.load(f)
hand["hand"].append(drawCard(channel))
hand["hit"] = True
hand["doubled"] = True
hand["bet"] += bet
handValue = calcHandValue(hand["hand"])
if handValue > 21:
hand["busted"] = True
if handNumber == 2:
data["blackjack games"][channel]["user hands"][user]["other hand"] = hand
elif handNumber == 3:
data["blackjack games"][channel]["user hands"][user]["third hand"] = hand
elif handNumber == 4:
data["blackjack games"][channel]["user hands"][user]["fourth hand"] = hand
else:
data["blackjack games"][channel]["user hands"][user] = hand
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
roundDone = isRoundDone(data["blackjack games"][channel])
return "Adding another "+str(bet)+" GwendoBucks to "+getName(user)+"'s bet and drawing another card.",str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
else:
logThis(user+" doesn't have enough GwendoBucks")
return "You don't have enough GwendoBucks",""
else:
logThis(user+" tried to double on round "+str(data["blackjack games"][channel]["round"]))
return "You can only double down on the first round",""
else:
logThis(user+" is already standing")
return "You can't double when you're standing",""
else:
logThis(user+" has already hit this round")
return "You've already hit this round",""
else:
logThis(user+" tried to double on the 0th round")
return "You can't double down before you see your cards",""
else:
logThis(user+" didn't specify a hand")
return "You need to specify which hand"
else:
logThis(user+" tried to double without being in the game")
return "You can't double when you're not in the game",""
# When players try to stand
def blackjackStand(channel,user,handNumber = 0):
@ -375,62 +319,33 @@ def blackjackStand(channel,user,handNumber = 0):
data = json.load(f)
if user in data["blackjack games"][channel]["user hands"]:
if data["blackjack games"][channel]["user hands"][user]["split"] == 0:
hand = data["blackjack games"][channel]["user hands"][user]
handNumber = 0
else:
if handNumber != 0:
if handNumber == 1:
hand = data["blackjack games"][channel]["user hands"][user]
elif handNumber == 2:
hand = data["blackjack games"][channel]["user hands"][user]["other hand"]
elif handNumber == 3:
hand = data["blackjack games"][channel]["user hands"][user]["third hand"]
elif handNumber == 4:
hand = data["blackjack games"][channel]["user hands"][user]["fourth hand"]
else:
logThis(user+" tried to hit without specifying which hand")
return "You have to specify the hand you're hitting with."
else:
logThis(user+" tried to hit without specifying which hand")
return "You have to specify the hand you're hitting with."
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
hand["standing"] = True
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
hand, handNumber = getHandNumber(data["blackjack games"][channel]["user hands"][user],handNumber)
response = "accept"
roundDone = True
if hand != None:
if data["blackjack games"][channel]["round"] > 0:
if hand["hit"] == False:
if hand["standing"] == False:
hand["standing"] = True
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
for person in data["blackjack games"][channel]["user hands"].values():
if person["hit"] == False and person["standing"] == False:
roundDone = False
if person["split"] > 0:
if person["other hand"]["hit"] == False and person["other hand"]["standing"] == False:
roundDone = False
response = "accept"
roundDone = isRoundDone(data["blackjack games"][channel])
if person["split"] > 1:
if person["third hand"]["hit"] == False and person["third hand"]["standing"] == False:
roundDone = False
if person["split"] > 2:
if person["fourth hand"]["hit"] == False and person["fourth hand"]["standing"] == False:
roundDone = False
return response + str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
return response + str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
else:
logThis(user+" is already standing")
return "You're already standing"
else:
logThis(user+" is already standing")
return "You're already standing"
logThis(user+" has already hit this round")
return "You've already hit this round"
else:
logThis(user+" has already hit this round")
return "You've already hit this round"
logThis(user+" tried to stand on the first round")
return "You can't stand before you see your cards"
else:
logThis(user+" tried to stand on the first round")
return "You can't stand before you see your cards"
logThis(user+" didn't specify a hand")
return "You need to specify which hand"
else:
logThis(user+" tried to stand without being in the game")
return "You have to enter the game before you can stand"
@ -526,23 +441,7 @@ def blackjackSplit(channel,user,handNumber = 0):
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
roundDone = True
for person in data["blackjack games"][channel]["user hands"].values():
if person["hit"] == False and person["standing"] == False:
roundDone = False
if person["split"] > 0:
if person["other hand"]["hit"] == False and person["other hand"]["standing"] == False:
roundDone = False
if person["split"] > 1:
if person["third hand"]["hit"] == False and person["third hand"]["standing"] == False:
roundDone = False
if person["split"] > 2:
if person["fourth hand"]["hit"] == False and person["fourth hand"]["standing"] == False:
roundDone = False
roundDone = isRoundDone(data["blackjack games"][channel])
return "Splitting "+getName(user)+"'s hand into 2. Adding their original bet to the second hand. You can use \"!Blackjack hit/stand/double 1\" and \"!Blackjack hit/stand/double 2\" to play the different hands.",str(roundDone)[0] + str(data["blackjack games"][channel]["round"])
else:
@ -744,4 +643,47 @@ def calcWinnings(hand, dealerValue, topLevel, dealerBlackjack, dealerBusted):
netWinnings += netWinningsTemp
reason += reasonTemp
return winnings, netWinnings, reason
return winnings, netWinnings, reason
def getHandNumber(user,handNumber):
try:
hand = None
if user["split"] == 0:
hand = user
handNumber = 0
else:
if handNumber != 0:
if handNumber == 1:
hand = user
elif handNumber == 2:
hand = user["other hand"]
elif handNumber == 3:
hand = user["third hand"]
elif handNumber == 4:
hand = user["fourth hand"]
return hand, handNumber
except:
logThis("Problem with getHandNumber() (error code 1322)")
def isRoundDone(game):
roundDone = True
for person in game["user hands"].values():
if person["hit"] == False and person["standing"] == False:
roundDone = False
if person["split"] > 0:
if person["other hand"]["hit"] == False and person["other hand"]["standing"] == False:
roundDone = False
if person["split"] > 1:
if person["third hand"]["hit"] == False and person["third hand"]["standing"] == False:
roundDone = False
if person["split"] > 2:
if person["fourth hand"]["hit"] == False and person["fourth hand"]["standing"] == False:
roundDone = False
return roundDone

View File

@ -22,7 +22,7 @@ def drawImage(channel):
dealerBusted = data["blackjack games"][channel]["dealer busted"]
dealerBlackjack = data["blackjack games"][channel]["dealer blackjack"]
try:
if data["blackjack games"][channel]["all standing"] == False:
dealerHand = drawHand(data["blackjack games"][channel]["dealer hand"],True,False,False)
@ -36,7 +36,7 @@ def drawImage(channel):
for x in range(len(hands)):
key, value = list(hands.items())[x]
key = getName(key)
logThis("drawing "+key+"'s hand")
#logThis("Drawing "+key+"'s hand")
userHand = drawHand(value["hand"],False,value["busted"],value["blackjack"])
try:
if value["split"] == 3:

View File

@ -20,6 +20,9 @@ def drawImage(channel):
exampleCircles = 100
w, h = 2800,2000
backgroundColor = (128,128,128,255)
outlineColor = (0,0,0)
player1Color = (200,0,0)
player2Color = (255,255,0)
boardColor = (0,0,170)
placeSize = 285
white = (255,255,255,160)
@ -48,35 +51,33 @@ def drawImage(channel):
# 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=(0,0,0),width=outlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=(0,0,0),width=outlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=(0,0,0),width=outlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=(0,0,0),width=outlineSize)
d.ellipse([(border,border),(border+cornerSize,border+cornerSize)],fill=boardColor,outline=outlineColor,width=outlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=outlineColor,width=outlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=outlineColor,width=outlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=outlineColor,width=outlineSize)
# - Rectangle:
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=(0,0,0),width=outlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=(0,0,0),width=outlineSize)
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=outlineColor,width=outlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=outlineColor,width=outlineSize)
# - 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.ellipse([(border+outlineSize,border+outlineSize),(border+cornerSize-outlineSize,border+cornerSize-outlineSize)],fill=boardColor)
d.ellipse([(w-(border+cornerSize)+outlineSize,h-(border+cornerSize)+outlineSize),(w-border-outlineSize,h-border-outlineSize)],fill=boardColor)
d.ellipse([(border+outlineSize,h-(border+cornerSize)+outlineSize),(border+cornerSize-outlineSize,h-border-outlineSize)],fill=boardColor)
d.ellipse([(w-(border+cornerSize)+outlineSize,border+outlineSize),(w-border-outlineSize,border+cornerSize-outlineSize)],fill=boardColor)
d.rectangle([(border+math.floor(cornerSize/2),border+outlineSize),(w-(border+math.floor(cornerSize/2)),h-(border+outlineSize))],fill=boardColor)
d.rectangle([(border+outlineSize,border+math.floor(cornerSize/2)),(w-(border+outlineSize),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
for line in range(len(board)):
for place in range(len(board[line])):
piece = board[line][place]
if piece == 1:
pieceColor = (255,255,0)
pieceColor = player1Color
elif piece == 2:
pieceColor = (200,0,0)
pieceColor = player2Color
else:
pieceColor = backgroundColor
startx = pieceStartx + placeGridSize[0]*place
starty = pieceStarty + placeGridSize[1]*line
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=(0,0,0),width=outlineSize)
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=outlineColor,width=outlineSize)
if data["4 in a row games"][channel]["winner"] != 0:
coordinates = data["4 in a row games"][channel]["win coordinates"]
@ -120,8 +121,7 @@ def drawImage(channel):
winBar = winBar.rotate(diagonalAngle,expand=1)
startx -= placeGridSize[0]*3 + border
starty -= gridBorder + border
mask = winBar.copy()#.convert("L")
#mask.putalpha(128)
#mask.save("test.png")
@ -133,11 +133,11 @@ def drawImage(channel):
textPadding = 20
exampleHeight = h - border + int((bottomBorder+border)/2) - int(exampleCircles/2)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=(255,255,0),outline=(0,0,0),width=3)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=player1Color,outline=outlineColor,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=(255,0,0),outline=(0,0,0),width=3)
d.ellipse([(w-border-exampleCircles-textWidth-textPadding,exampleHeight),(w-border-textWidth-textPadding),(exampleHeight+exampleCircles)],fill=player2Color,outline=outlineColor,width=3)
d.text((w-border-textWidth,exampleHeight),player2,font=fnt,fill=(0,0,0))

View File

@ -18,13 +18,13 @@ def addMoney(user,amount):
logThis("adding "+str(amount)+" to "+user+"'s account")
with open("resources/users.json", "r") as f:
data = json.load(f)
if user in data:
points = data[user]["money"]
data[user]["money"] = points + amount
else:
logThis("Error adding money")
with open("resources/users.json", "w") as f:
json.dump(data,f,indent=4)
@ -32,11 +32,11 @@ def addMoney(user,amount):
def giveMoney(user,targetUser,amount):
with open("resources/users.json", "r") as f:
data = json.load(f)
targetUser = getID(targetUser)
if amount > 0:
if targetUser.startswith("#"):
if targetUser != None:
if user in data:
if data[user]["money"] >= amount:
addMoney(user,-1 * amount)

141
funcs/games/monopoly.py Normal file
View File

@ -0,0 +1,141 @@
import json, random
from funcs import getName, logThis
from . import monopolyDraw
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)
if channel not in data:
buildings = [0] * 40
data[channel] = {"players" : {}, "player list" : [],"turn" : 0, "buildings" : buildings, "last roll" : [0,0], "started" : False}
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(data,f,indent=4)
try:
monopolyDraw.drawImage(channel)
except:
logThis("Error drawing board (error code 1640)")
return "Started a monopoly game. Use \"!monopoly join\" to join within the next minute.", True, False, True, True
else:
return "There's already a monopoly game going on.", False, False, False, False
def monopolyJoin(channel,user):
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
if channel in data:
if not data[channel]["started"]:
if user not in data[channel]["players"]:
if len(data[channel]["players"]) < 6:
data[channel]["players"][user] = {"position" : 0, "properties" : [], "money" : 1500, "doubles" : 0}
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(data,f,indent=4)
return getName(user)+" has joined the game.", False, False, False, False
else:
return "There are already 6 players in the game.", False, False, False, False
else:
return "You're already in the game!", False, False, False, False
else:
return "It's too late to join.", False, False, False, False
else:
return "There's no game going on.", False, False, False, False
def parseMonopoly(command, channel, user):
logThis("Parsing "+command)
commands = command.split()
if command in [" ", ""] or commands[0] == "start":
try:
return monopolyStart(channel)
except:
logThis("Error starting game (error code 1620)")
elif commands[0] == "join":
try:
return monopolyJoin(channel,user)
except:
logThis("Error joining game (error code 1630)")
elif commands[0] == "roll":
try:
return monopolyRoll(channel,user)
except:
logThis("Error rolling (error code 1650)")
else:
return "I didn't understand that (error code 1602)", False, False, False, False
def monopolyContinue(channel):
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
if channel in data:
if data[channel]["started"] == False:
data[channel]["started"] = True
playerList = list(data[channel]["players"].keys())
random.shuffle(playerList)
data[channel]["player list"] = playerList
turn = 0
else:
if data[channel]["last roll"][0] == data[channel]["last roll"][1]:
turn = data[channel]["turn"]
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)")
message = "It's "+getName(playerList[turn])+"'s turn. Use the 🎲 reaction to roll. You can also use \"!monopoly trade\" at any time."
return message, True, True, False
def monopolyRoll(channel,user):
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
turn = data[channel]["turn"]
currentPlayer = data[channel]["player list"][turn]
if user == currentPlayer:
rolls = [random.randint(1,6),random.randint(1,6)]
message = getName(user)+" rolled a "+str(rolls[0])+" and a "+str(rolls[1])+"."
if rolls[0] == rolls[1]:
message += " Doubbles!"
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"]+"."
data[channel]["players"][user]["position"] = newPosition
data[channel]["last roll"] = rolls
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(data,f,indent=4)
try:
monopolyDraw.drawImage(channel)
except:
logThis("Error drawing board (error code 1640)")
return message, True, True, False, True
else: return "", False, False, False, False

View File

@ -0,0 +1,57 @@
import math, json
from funcs import logThis
from PIL import Image, ImageDraw
w, h = 1440, 1440
largeSpace = 191
smallSpace = math.floor((w - 2*largeSpace)/9)
avatarSize = 50
avatarHalf = math.floor(avatarSize/2)
def drawImage(channel):
logThis("Drawing monopoly board for "+channel)
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
board = Image.open("resources/games/monopolyBoard.png")
d = ImageDraw.Draw(board,"RGBA")
for key, value in list(data[channel]["players"].items()):
logThis("Drawing "+key)
try:
x, y = getPosition(value["position"])
except:
logThis("Error getting position (error code 1641)")
print(str(x)+", "+str(y))
d.ellipse([(x-avatarHalf,y-avatarHalf),(x+avatarHalf,y+avatarHalf)],fill=(255,0,0))
board.save("resources/games/monopolyBoards/monopolyBoard"+channel+".png")
def getPosition(positionNumber):
print(positionNumber)
x, y = 0, 0
if positionNumber == 0 or positionNumber >= 30:
x = math.floor(largeSpace/2)
elif positionNumber > 0 and positionNumber < 10:
x = math.floor(largeSpace - (smallSpace/2)) + (smallSpace*positionNumber)
elif positionNumber >= 10 and positionNumber <= 20:
x = w - math.floor(largeSpace/2)
elif positionNumber > 20 and positionNumber < 30:
x = w - math.floor(largeSpace - (smallSpace/2)) - (smallSpace*(positionNumber - 20))
if positionNumber >= 0 and positionNumber <= 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

View File

@ -13,6 +13,7 @@ logging.basicConfig(filename="gwendolyn.log", level=logging.INFO)
# Capitalizes all words except some of them
no_caps_list = ["of","the"]
def cap(s):
# Capitalizes a strink like a movie title
word_number = 0
lst = s.split()
res = ''
@ -25,7 +26,7 @@ def cap(s):
return res
def time_in_range(start, end, x):
"""Return true if x is in the range [start, end]"""
# Return true if x is in the range [start, end]
if start <= end:
return start <= x <= end
else:
@ -134,146 +135,45 @@ def findWikiPage(search : str):
logThis("Couldn't find the page (error code 1002)")
return "", "Couldn't find page (error code 1002)", ""
def makeJsonFile(path,content):
# Creates json file if it doesn't exist
try:
f = open(path,"r")
except:
logThis(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path,"w") as f:
json.dump(content,f,indent = 4)
finally:
f.close()
def makeTxtFile(path,content):
# Creates txt file if it doesn't exist
try:
f = open(path,"r")
except:
logThis(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path,"w") as f:
f.write(content)
finally:
f.close()
def makeFolder(path):
if os.path.isdir(path) == False:
os.makedirs(path)
logThis("The "+path.split("/")[-1]+" directory didn't exist")
def makeFiles():
# Creates swcharacters.json if it doesn't exist
try:
f = open("resources/starWars/swcharacters.json","r")
except:
logThis("swcharacters.json didn't exist. Making it now.")
emptyDict = {}
with open("resources/starWars/swcharacters.json","w") as f:
json.dump(emptyDict,f,indent = 4)
finally:
f.close()
with open("resources/startingFiles.json") as f:
data = json.load(f)
# Creates games.json if it doesn't exist
try:
f = open("resources/games/games.json","r")
except:
logThis("games.json didn't exist. Making it now.")
data = {"trivia questions":{},"blackjack games":{},"4 in a row games": {},"users":{}}
with open("resources/games/games.json","w") as f:
json.dump(data,f,indent = 4)
finally:
f.close()
for path, content in data["json"].items():
makeJsonFile(path,content)
# Creates hexGames.json if it doesn't exist
try:
f = open("resources/games/hexGames.json","r")
except:
logThis("hexGames.json didn't exist. Making it now.")
data = {}
with open("resources/games/hexGames.json","w") as f:
json.dump(data,f,indent = 4)
finally:
f.close()
# Creates monsters.json if it doesn't exist
try:
f = open("resources/lookup/monsters.json","r")
except:
logThis("monsters.json didn't exist. Making it now.")
with open("resources/lookup/lookupExamples.json") as f:
data = json.load(f)["monster"]
with open("resources/lookup/monsters.json","w") as f:
json.dump(data,f,indent = 4)
finally:
f.close()
# Creates spells.json if it doesn't exist
try:
f = open("resources/lookup/spells.json","r")
except:
logThis("spells.json didn't exist. Making it now.")
with open("resources/lookup/lookupExamples.json") as f:
data = json.load(f)["spell"]
with open("resources/lookup/spells.json","w") as f:
json.dump(data,f,indent = 4)
finally:
f.close()
for path, content in data["txt"].items():
makeTxtFile(path,content)
# Creates users.json if it doesn't exist
try:
f = open("resources/users.json","r")
except:
logThis("users.json didn't exist. Making it now.")
data = {}
with open("resources/users.json","w") as f:
json.dump(data,f,indent = 4)
finally:
f.close()
# Creates destinyPoints.txt if it doesn't exist
try:
f = open("resources/starWars/destinyPoints.txt","r")
except:
logThis("destinyPoints.txt didn't exist. Making it now.")
with open("resources/starWars/destinyPoints.txt","w") as f:
f.write("")
finally:
f.close()
# Creates movies.txt if it doesn't exist
try:
f = open("resources/movies.txt","r")
except:
logThis("movies.txt didn't exist. Making it now.")
with open("resources/movies.txt","w") as f:
f.write("The Room")
finally:
f.close()
# Creates names.txt if it doesn't exist
try:
f = open("resources/names.txt","r")
except:
logThis("names.txt didn't exist. Making it now.")
with open("resources/names.txt","w") as f:
f.write("Gandalf")
finally:
f.close()
# Creates token.txt if it doesn't exist
try:
f = open("token.txt","r")
except:
logThis("token.txt didn't exist. Write your bot token below, or in token.txt later.")
token = input()
with open("token.txt","w") as f:
f.write(token)
finally:
f.close()
# Creates the blackjacktables foulder if it doesn't exist
if os.path.isdir("resources/games/blackjackTables") == False:
os.makedirs("resources/games/blackjackTables")
logThis("The tables directory didn't exist")
# Creates the 4InARowBoards foulder if it doesn't exist
if os.path.isdir("resources/games/4InARowBoards") == False:
os.makedirs("resources/games/4InARowBoards")
logThis("The 4 in a row boards directory didn't exist")
# Creates the hexBoards foulder if it doesn't exist
if os.path.isdir("resources/games/hexBoards") == False:
os.makedirs("resources/games/hexBoards")
logThis("The Hex boards directory didn't exist")
# Creates the oldImages foulder if it doesn't exist
if os.path.isdir("resources/games/oldImages") == False:
os.makedirs("resources/games/oldImages")
logThis("The old images directory didn't exist")
# Creates the blackjackCards foulder if it doesn't exist
if os.path.isdir("resources/games/blackjackCards") == False:
os.makedirs("resources/games/blackjackCards")
logThis("The blackjack cards directory didn't exist")
# Creates the hilo foulder if it doesn't exist
if os.path.isdir("resources/games/hilo") == False:
os.makedirs("resources/games/hilo")
logThis("The hi-lo directory didn't exist")
for path in data["folder"]:
makeFolder(path)
# Replaces multiple things with the same thing
def replaceMultiple(mainString, toBeReplaces, newString):
@ -286,7 +186,7 @@ def replaceMultiple(mainString, toBeReplaces, newString):
return mainString
def emojiToNumber(emoji):
def emojiToCommand(emoji):
if emoji == "1":
return 1
elif emoji == "2":
@ -301,21 +201,21 @@ def emojiToNumber(emoji):
return 6
elif emoji == "7":
return 7
elif 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), "r") as 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)]["turn"]
print(user)
print(data["4 in a row games"][str(channel)]["players"][turn])
if user == data["4 in a row games"][str(channel)]["players"][turn]:
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")
@ -323,16 +223,31 @@ def fiarReactionTest(channel,message,user):
else:
return False, 0
def monopolyReactionTest(channel,message):
with open("resources/games/oldImages/monopoly"+str(channel.id), "r") as f:
oldImage = int(f.read())
if message.id == oldImage:
logThis("They reacted to the monopoly game")
return True
else:
return False
def stopServer():
with open("resources/games/games.json","r") as f:
data = json.load(f)
games = json.load(f)
data["trivia questions"] = {}
data["blackjack games"] = {}
data["4 in a row games"] = {}
games["trivia questions"] = {}
games["blackjack games"] = {}
games["4 in a row games"] = {}
with open("resources/games/games.json","w") as f:
json.dump(data,f,indent=4)
json.dump(games,f,indent=4)
emptyDict = {}
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(emptyDict,f,indent=4)
def deleteGame(gameType,channel):
with open("resources/games/games.json", "r") as f:

View File

@ -1,4 +1,4 @@
"""I stole this."""
"""Rolling dice."""
__all__ = ["roll_dice"]

View File

@ -1,560 +1,20 @@
import random
import re
import traceback
from heapq import nlargest, nsmallest
from math import floor
from re import IGNORECASE
import d20
import numexpr
class MyStringifier(d20.MarkdownStringifier):
from . import errors
#from funcs import logThis
def _str_expression(self, node):
VALID_OPERATORS = 'k|rr|ro|mi|ma|ra|e|p'
VALID_OPERATORS_ARRAY = VALID_OPERATORS.split('|')
VALID_OPERATORS_2 = re.compile('|'.join(["({})".format(i) for i in VALID_OPERATORS_ARRAY]))
DICE_PATTERN = re.compile(
r'^\s*(?:(?:(\d*d\d+)(?:(?:' + VALID_OPERATORS + r')(?:[lh<>]?\d+))*|(\d+)|([-+*/().=])?)\s*(\[.*\])?)(.*?)\s*$',
IGNORECASE)
def roll_dice(author : str, rollStr : str = "1d20"):
if rollStr == '0/0': # easter eggs
return("What do you expect me to do, destroy the universe?")
adv = 0
if re.search('(^|\s+)(adv|dis)(\s+|$)', rollStr) is not None:
adv = 1 if re.search('(^|\s+)adv(\s+|$)', rollStr) is not None else -1
rollStr = re.sub('(adv|dis)(\s+|$)', '', rollStr)
res = roll(rollStr, adv=adv)
out = res.result
outStr = author + ' :game_die:\n' + out
if len(outStr) > 1999:
outputs = author + ' :game_die:\n[Output truncated due to length]\n**Result:** ' + str(res.plain)
else:
outputs = outStr
return(outputs)
def list_get(index, default, l):
try:
a = l[index]
except IndexError:
a = default
return a
def roll(rollStr, adv: int = 0, rollFor='', inline=False, double=False, show_blurbs=True, **kwargs):
roller = Roll()
result = roller.roll(rollStr, adv, rollFor, inline, double, show_blurbs, **kwargs)
return result
def get_roll_comment(rollStr):
"""Returns: A two-tuple (dice without comment, comment)"""
try:
comment = ''
no_comment = ''
dice_set = re.split('([-+*/().=])', rollStr)
dice_set = [d for d in dice_set if not d in (None, '')]
#logThis("Found dice set: " + str(dice_set))
for index, dice in enumerate(dice_set):
match = DICE_PATTERN.match(dice)
#logThis("Found dice group: " + str(match.groups()))
no_comment += dice.replace(match.group(5), '')
if match.group(5):
comment = match.group(5) + ''.join(dice_set[index + 1:])
break
return no_comment, comment
except:
pass
return rollStr, ''
class Roll(object):
def __init__(self, parts=None):
if parts ==None:
parts = []
self.parts = parts
def get_crit(self):
"""Returns: 0 for no crit, 1 for 20, 2 for 1."""
try:
crit = next(p.get_crit() for p in self.parts if isinstance(p, SingleDiceGroup))
except StopIteration:
crit = 0
return crit
def get_total(self):
"""Returns: int"""
return numexpr.evaluate(''.join(p.get_eval() for p in self.parts if not isinstance(p, Comment)))
# # Dice Roller
def roll(self, rollStr, adv: int = 0, rollFor='', inline=False, double=False, show_blurbs=True, **kwargs):
try:
if '**' in rollStr:
raise errors.InvalidArgument("Exponents are currently disabled.")
self.parts = []
# split roll string into XdYoptsSel [comment] or Op
# set remainder to comment
# parse each, returning a SingleDiceResult
dice_set = re.split('([-+*/().=])', rollStr)
dice_set = [d for d in dice_set if not d in (None, '')]
#logThis("Found dice set: " + str(dice_set))
for index, dice in enumerate(dice_set):
match = DICE_PATTERN.match(dice)
#logThis("Found dice group: " + str(match.groups()))
# check if it's dice
if match.group(1):
roll = self.roll_one(dice.replace(match.group(5), ''), adv)
self.parts.append(roll)
# or a constant
elif match.group(2):
self.parts.append(Constant(value=int(match.group(2)), annotation=match.group(4)))
# or an operator
elif not match.group(5):
self.parts.append(Operator(op=match.group(3), annotation=match.group(4)))
if match.group(5):
self.parts.append(Comment(match.group(5) + ''.join(dice_set[index + 1:])))
break
# calculate total
crit = self.get_crit()
try:
total = self.get_total()
except SyntaxError:
raise errors.InvalidArgument("No dice found to roll.")
rolled = ' '.join(str(res) for res in self.parts if not isinstance(res, Comment))
if rollFor =='':
rollFor = ''.join(str(c) for c in self.parts if isinstance(c, Comment))
# return final solution
if not inline:
# Builds end result while showing rolls
reply = ' '.join(
str(res) for res in self.parts if not isinstance(res, Comment)) + '\n**Total:** ' + str(
floor(total))
skeletonReply = reply
rollFor = rollFor if rollFor != '' else 'Result'
reply = '**{}:** '.format(rollFor) + reply
if show_blurbs:
if adv == 1:
reply += '\n**Rolled with Advantage**'
elif adv == -1:
reply += '\n**Rolled with Disadvantage**'
if crit == 1:
critStr = "\n_**Critical Hit!**_ "
reply += critStr
elif crit == 2:
critStr = "\n_**Critical Fail!**_ "
reply += critStr
else:
# Builds end result while showing rolls
reply = ' '.join(str(res) for res in self.parts if not isinstance(res, Comment)) + ' = `' + str(
floor(total)) + '`'
skeletonReply = reply
rollFor = rollFor if rollFor != '' else 'Result'
reply = '**{}:** '.format(rollFor) + reply
if show_blurbs:
if adv == 1:
reply += '\n**Rolled with Advantage**'
elif adv == -1:
reply += '\n**Rolled with Disadvantage**'
if crit == 1:
critStr = "\n_**Critical Hit!**_ "
reply += critStr
elif crit == 2:
critStr = "\n_**Critical Fail!**_ "
reply += critStr
reply = re.sub(' +', ' ', reply)
skeletonReply = re.sub(' +', ' ', str(skeletonReply))
return DiceResult(result=int(floor(total)), verbose_result=reply, crit=crit, rolled=rolled,
skeleton=skeletonReply, raw_dice=self)
except Exception as ex:
if not isinstance(ex, (SyntaxError, KeyError, errors.AvraeException)):
#logThis('Error in roll() caused by roll {}:'.format(rollStr))
traceback.print_exc()
return DiceResult(verbose_result="Invalid input: {}".format(ex))
def roll_one(self, dice, adv: int = 0):
result = SingleDiceGroup()
result.rolled = []
# splits dice and comments
split = re.match(r'^([^\[\]]*?)\s*(\[.*\])?\s*$', dice)
dice = split.group(1).strip()
annotation = split.group(2)
result.annotation = annotation if annotation != None else ''
# Recognizes dice
obj = re.findall('\d+', dice)
obj = [int(x) for x in obj]
numArgs = len(obj)
ops = []
if numArgs == 1:
if not dice.startswith('d'):
raise errors.InvalidArgument('Please pass in the value of the dice.')
numDice = 1
diceVal = obj[0]
if adv != 0 and diceVal == 20:
numDice = 2
ops = ['k', 'h1'] if adv ==1 else ['k', 'l1']
elif numArgs == 2:
numDice = obj[0]
diceVal = obj[-1]
if adv != 0 and diceVal == 20:
ops = ['k', 'h' + str(numDice)] if adv ==1 else ['k', 'l' + str(numDice)]
numDice = numDice * 2
else: # split into xdy and operators
numDice = obj[0]
diceVal = obj[1]
dice = re.split('(\d+d\d+)', dice)[-1]
ops = VALID_OPERATORS_2.split(dice)
ops = [a for a in ops if a != None]
# dice repair/modification
if numDice > 300 or diceVal < 1:
raise errors.InvalidArgument('Too many dice rolled.')
result.max_value = diceVal
result.num_dice = numDice
result.operators = ops
for _ in range(numDice):
try:
tempdice = SingleDice()
tempdice.value = random.randint(1, diceVal)
tempdice.rolls = [tempdice.value]
tempdice.max_value = diceVal
tempdice.kept = True
result.rolled.append(tempdice)
except:
result.rolled.append(SingleDice())
if ops != None:
rerollList = []
reroll_once = []
keep = None
to_explode = []
to_reroll_add = []
valid_operators = VALID_OPERATORS_ARRAY
last_operator = None
for index, op in enumerate(ops):
if last_operator != None and op in valid_operators and not op == last_operator:
result.reroll(reroll_once, 1)
reroll_once = []
result.reroll(rerollList, greedy=True)
rerollList = []
result.keep(keep)
keep = None
result.reroll(to_reroll_add, 1, keep_rerolled=True, unique=True)
to_reroll_add = []
result.reroll(to_explode, greedy=True, keep_rerolled=True)
to_explode = []
if op == 'rr':
rerollList += parse_selectors([list_get(index + 1, 0, ops)], result, greedy=True)
if op == 'k':
keep = [] if keep ==None else keep
keep += parse_selectors([list_get(index + 1, 0, ops)], result)
if op == 'p':
keep = [] if keep ==None else keep
keep += parse_selectors([list_get(index + 1, 0, ops)], result, inverse=True)
if op == 'ro':
reroll_once += parse_selectors([list_get(index + 1, 0, ops)], result)
if op == 'mi':
_min = list_get(index + 1, 0, ops)
for r in result.rolled:
if r.value < int(_min):
r.update(int(_min))
if op == 'ma':
_max = list_get(index + 1, 0, ops)
for r in result.rolled:
if r.value > int(_max):
r.update(int(_max))
if op == 'ra':
to_reroll_add += parse_selectors([list_get(index + 1, 0, ops)], result)
if op == 'e':
to_explode += parse_selectors([list_get(index + 1, 0, ops)], result, greedy=True)
if op in valid_operators:
last_operator = op
result.reroll(reroll_once, 1)
result.reroll(rerollList, greedy=True)
result.keep(keep)
result.reroll(to_reroll_add, 1, keep_rerolled=True, unique=True)
result.reroll(to_explode, greedy=True, keep_rerolled=True)
return result
class Part:
"""Class to hold one part of the roll string."""
pass
class SingleDiceGroup(Part):
def __init__(self, num_dice: int = 0, max_value: int = 0, rolled=None, annotation: str = "", result: str = "",
operators=None):
if operators ==None:
operators = []
if rolled ==None:
rolled = []
self.num_dice = num_dice
self.max_value = max_value
self.rolled = rolled # list of SingleDice
self.annotation = annotation
self.result = result
self.operators = operators
def keep(self, rolls_to_keep):
if rolls_to_keep ==None: return
for _roll in self.rolled:
if not _roll.value in rolls_to_keep:
_roll.kept = False
elif _roll.kept:
rolls_to_keep.remove(_roll.value)
def reroll(self, rerollList, max_iterations=1000, greedy=False, keep_rerolled=False, unique=False):
if not rerollList: return # don't reroll nothing - minor optimization
if unique:
rerollList = list(set(rerollList)) # remove duplicates
if len(rerollList) > 100:
raise OverflowError("Too many dice to reroll (max 100)")
last_index = 0
count = 0
should_continue = True
while should_continue: # let's only iterate 250 times for sanity
should_continue = False
if any(d.value in set(rerollList) for d in self.rolled[last_index:] if d.kept and not d.exploded):
should_continue = True
to_extend = []
for r in self.rolled[last_index:]: # no need to recheck everything
count += 1
if count > max_iterations:
should_continue = False
if r.value in rerollList and r.kept and not r.exploded:
try:
tempdice = SingleDice()
tempdice.value = random.randint(1, self.max_value)
tempdice.rolls = [tempdice.value]
tempdice.max_value = self.max_value
tempdice.kept = True
to_extend.append(tempdice)
if not keep_rerolled:
r.drop()
else:
r.explode()
except:
to_extend.append(SingleDice())
if not keep_rerolled:
r.drop()
else:
r.explode()
if not greedy:
rerollList.remove(r.value)
last_index = len(self.rolled)
self.rolled.extend(to_extend)
def get_total(self):
"""Returns:
int - The total value of the dice."""
return sum(r.value for r in self.rolled if r.kept)
def get_eval(self):
return str(self.get_total())
def get_num_kept(self):
return sum(1 for r in self.rolled if r.kept)
def get_crit(self):
"""Returns:
int - 0 for no crit, 1 for crit, 2 for crit fail."""
if self.get_num_kept() == 1 and self.max_value == 20:
if self.get_total() == 20:
return 1
elif self.get_total() == 1:
return 2
return 0
def __str__(self):
return "{0.num_dice}d{0.max_value}{1} ({2}) {0.annotation}".format(
self, ''.join(self.operators), ', '.join(str(r) for r in self.rolled))
def to_dict(self):
return {'type': 'dice', 'dice': [d.to_dict() for d in self.rolled], 'annotation': self.annotation,
'value': self.get_total(), 'is_crit': self.get_crit(), 'num_kept': self.get_num_kept(),
'text': str(self), 'num_dice': self.num_dice, 'dice_size': self.max_value, 'operators': self.operators}
class SingleDice:
def __init__(self, value: int = 0, max_value: int = 0, kept: bool = True, exploded: bool = False):
self.value = value
self.max_value = max_value
self.kept = kept
self.rolls = [value] # list of ints (for X -> Y -> Z)
self.exploded = exploded
def drop(self):
self.kept = False
def explode(self):
self.exploded = True
def update(self, new_value):
self.value = new_value
self.rolls.append(new_value)
def __str__(self):
formatted_rolls = [str(r) for r in self.rolls]
if int(formatted_rolls[-1]) == self.max_value or int(formatted_rolls[-1]) == 1:
formatted_rolls[-1] = '**' + formatted_rolls[-1] + '**'
if self.exploded:
formatted_rolls[-1] = '__' + formatted_rolls[-1] + '__'
if self.kept:
return ' -> '.join(formatted_rolls)
if node.comment == None:
resultText = "Result"
else:
return '~~' + ' -> '.join(formatted_rolls) + '~~'
resultText = node.comment.capitalize()
def __repr__(self):
return "<SingleDice object: value={0.value}, max_value={0.max_value}, kept={0.kept}, rolls={0.rolls}>".format(
self)
return f"**{resultText}**: {self._stringify(node.roll)}\n**Total**: {int(node.total)}"
def to_dict(self):
return {'type': 'single_dice', 'value': self.value, 'size': self.max_value, 'is_kept': self.kept,
'rolls': self.rolls, 'exploded': self.exploded}
def roll_dice(user, rollString):
while len(rollString) > 1 and rollString[0] == " ":
rollString = rollString[1:]
return user+" :game_die:\n"+str(d20.roll(rollString, allow_comments=True,stringifier=MyStringifier()))
class Constant(Part):
def __init__(self, value: int = 0, annotation: str = ""):
self.value = value
self.annotation = annotation if annotation != None else ''
def __str__(self):
return "{0.value} {0.annotation}".format(self)
def get_eval(self):
return str(self.value)
def to_dict(self):
return {'type': 'constant', 'value': self.value, 'annotation': self.annotation}
class Operator(Part):
def __init__(self, op: str = "+", annotation: str = ""):
self.op = op if op != None else ''
self.annotation = annotation if annotation != None else ''
def __str__(self):
return "{0.op} {0.annotation}".format(self)
def get_eval(self):
return self.op
def to_dict(self):
return {'type': 'operator', 'value': self.op, 'annotation': self.annotation}
class Comment(Part):
def __init__(self, comment: str = ""):
self.comment = comment
def __str__(self):
return self.comment.strip()
def to_dict(self):
return {'type': 'comment', 'value': self.comment}
def parse_selectors(opts, res, greedy=False, inverse=False):
"""Returns a list of ints."""
for o in range(len(opts)):
if opts[o][0] =='h':
opts[o] = nlargest(int(opts[o].split('h')[1]), (d.value for d in res.rolled if d.kept))
elif opts[o][0] =='l':
opts[o] = nsmallest(int(opts[o].split('l')[1]), (d.value for d in res.rolled if d.kept))
elif opts[o][0] =='>':
if greedy:
opts[o] = list(range(int(opts[o].split('>')[1]) + 1, res.max_value + 1))
else:
opts[o] = [d.value for d in res.rolled if d.value > int(opts[o].split('>')[1])]
elif opts[o][0] =='<':
if greedy:
opts[o] = list(range(1, int(opts[o].split('<')[1])))
else:
opts[o] = [d.value for d in res.rolled if d.value < int(opts[o].split('<')[1])]
out = []
for o in opts:
if isinstance(o, list):
out.extend(int(l) for l in o)
elif not greedy:
out.extend(int(o) for a in res.rolled if a.value ==int(o) and a.kept)
else:
out.append(int(o))
if not inverse:
return out
inverse_out = []
for rolled in res.rolled:
if rolled.kept and rolled.value in out:
out.remove(rolled.value)
elif rolled.kept:
inverse_out.append(rolled.value)
return inverse_out
class DiceResult:
"""Class to hold the output of a dice roll."""
def __init__(self, result: int = 0, verbose_result: str = '', crit: int = 0, rolled: str = '', skeleton: str = '',
raw_dice: Roll = None):
self.plain = result
self.total = result
self.result = verbose_result
self.crit = crit
self.rolled = rolled
self.skeleton = skeleton if skeleton != '' else verbose_result
self.raw_dice = raw_dice # Roll
def __str__(self):
return self.result
def __repr__(self):
return '<DiceResult object: total={}>'.format(self.total)
def consolidated(self):
"""Gets the most simplified version of the roll string."""
if self.raw_dice ==None:
return "0"
parts = [] # list of (part, annotation)
last_part = ""
for p in self.raw_dice.parts:
if isinstance(p, SingleDiceGroup):
last_part += str(p.get_total())
else:
last_part += str(p)
if not isinstance(p, Comment) and p.annotation:
parts.append((last_part, p.annotation))
last_part = ""
if last_part:
parts.append((last_part, ""))
to_roll = ""
last_annotation = ""
out = ""
for numbers, annotation in parts:
if annotation and annotation != last_annotation and to_roll:
out += f"{roll(to_roll).total:+} {last_annotation}"
to_roll = ""
if annotation:
last_annotation = annotation
to_roll += numbers
if to_roll:
out += f"{roll(to_roll).total:+} {last_annotation}"
out = out.strip('+ ')
return out
if __name__ == '__main__':
while True:
print(roll(input().strip()))

View File

@ -1,162 +0,0 @@
class AvraeException(Exception):
"""A base exception class."""
def __init__(self, msg):
super().__init__(msg)
class NoCharacter(AvraeException):
"""Raised when a user has no active character."""
def __init__(self):
super().__init__("You have no character active.")
class NoActiveBrew(AvraeException):
"""Raised when a user has no active homebrew of a certain type."""
def __init__(self):
super().__init__("You have no homebrew of this type active.")
class ExternalImportError(AvraeException):
"""Raised when something fails to import."""
def __init__(self, msg):
super().__init__(msg)
class InvalidArgument(AvraeException):
"""Raised when an argument is invalid."""
pass
class EvaluationError(AvraeException):
"""Raised when a cvar evaluation causes an error."""
def __init__(self, original):
super().__init__(f"Error evaluating expression: {original}")
self.original = original
class FunctionRequiresCharacter(AvraeException):
"""
Raised when a function that requires a character is called without one.
"""
def __init__(self, msg=None):
super().__init__(msg or "This alias requires an active character.")
class OutdatedSheet(AvraeException):
"""Raised when a feature is used that requires an updated sheet."""
def __init__(self, msg=None):
super().__init__(msg or "This command requires an updated character sheet. Try running `!update`.")
class NoSpellDC(AvraeException):
def __init__(self):
super().__init__("No spell save DC found.")
class NoSpellAB(AvraeException):
def __init__(self):
super().__init__("No spell attack bonus found.")
class InvalidSaveType(AvraeException):
def __init__(self):
super().__init__("Invalid save type.")
class ConsumableException(AvraeException):
"""A base exception for consumable exceptions to stem from."""
pass
class ConsumableNotFound(ConsumableException):
"""Raised when a consumable is not found."""
def __init__(self):
super().__init__("The requested counter does not exist.")
class CounterOutOfBounds(ConsumableException):
"""Raised when a counter is set to a value out of bounds."""
def __init__(self):
super().__init__("The new value is out of bounds.")
class NoReset(ConsumableException):
"""Raised when a consumable without a reset is reset."""
def __init__(self):
super().__init__("The counter does not have a reset value.")
class InvalidSpellLevel(ConsumableException):
"""Raised when a spell level is invalid."""
def __init__(self):
super().__init__("The spell level is invalid.")
class SelectionException(AvraeException):
"""A base exception for message awaiting exceptions to stem from."""
pass
class NoSelectionElements(SelectionException):
"""Raised when get_selection() is called with no choices."""
def __init__(self, msg=None):
super().__init__(msg or "There are no choices to select from.")
class SelectionCancelled(SelectionException):
"""Raised when get_selection() is cancelled or times out."""
def __init__(self):
super().__init__("Selection timed out or was cancelled.")
class CombatException(AvraeException):
"""A base exception for combat-related exceptions to stem from."""
pass
class CombatNotFound(CombatException):
"""Raised when a channel is not in combat."""
def __init__(self):
super().__init__("This channel is not in combat.")
class RequiresContext(CombatException):
"""Raised when a combat is committed without context."""
def __init__(self):
super().__init__("Combat not contextualized.")
class ChannelInCombat(CombatException):
"""Raised when a combat is started with an already active combat."""
def __init__(self):
super().__init__("Channel already in combat.")
class CombatChannelNotFound(CombatException):
"""Raised when a combat's channel is not in the channel list."""
def __init__(self):
super().__init__("Combat channel does not exist.")
class NoCombatants(CombatException):
"""Raised when a combat tries to advance turn with no combatants."""
def __init__(self):
super().__init__("There are no combatants.")