967 lines
43 KiB
Python
967 lines
43 KiB
Python
import random
|
|
import math
|
|
import datetime
|
|
import asyncio
|
|
import discord
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
from shutil import copyfile
|
|
|
|
from utils import replaceMultiple
|
|
|
|
class Blackjack():
|
|
def __init__(self,bot):
|
|
self.bot = bot
|
|
self.draw = DrawBlackjack(bot)
|
|
|
|
# Shuffles the blackjack cards
|
|
def blackjackShuffle(self, decks, channel):
|
|
self.bot.log("Shuffling the blackjack deck")
|
|
|
|
with open("resources/games/deckOfCards.txt","r") as f:
|
|
deck = f.read()
|
|
|
|
allDecks = deck.split("\n") * decks
|
|
random.shuffle(allDecks)
|
|
|
|
self.bot.database["blackjack cards"].update_one({"_id":channel},{"$set":{"_id":channel,"cards":allDecks}},upsert=True)
|
|
|
|
# Creates hilo file
|
|
self.bot.log("creating hilo doc for "+channel)
|
|
data = 0
|
|
self.bot.database["hilo"].update_one({"_id":channel},{"$set":{"_id":channel,"hilo":data}},upsert=True)
|
|
|
|
return
|
|
|
|
# Calculates the value of a blackjack hand
|
|
def calcHandValue(self, hand : list):
|
|
self.bot.log("Calculating hand value")
|
|
values = []
|
|
values.append(0)
|
|
|
|
for card in hand:
|
|
cardValue = card[0]
|
|
cardValue = replaceMultiple(cardValue,["0","k","q","j"],"10")
|
|
if cardValue == "a":
|
|
length = len(values)
|
|
for x in range(length):
|
|
values.append(values[x] + 11)
|
|
values[x] += 1
|
|
else:
|
|
for x in range(len(values)):
|
|
values[x] += int(cardValue)
|
|
|
|
values.sort()
|
|
|
|
handValue = values[0]
|
|
for value in values:
|
|
if value <= 21:
|
|
handValue = value
|
|
|
|
self.bot.log("Calculated "+str(hand)+" to be "+str(handValue))
|
|
|
|
return handValue
|
|
|
|
# Draws a card from the deck
|
|
def drawCard(self, channel):
|
|
self.bot.log("drawing a card")
|
|
|
|
drawnCard = self.bot.database["blackjack cards"].find_one({"_id":channel})["cards"][0]
|
|
self.bot.database["blackjack cards"].update_one({"_id":channel},{"$pop":{"cards":-1}})
|
|
value = self.calcHandValue([drawnCard])
|
|
|
|
if value <= 6:
|
|
self.bot.database["hilo"].update_one({"_id":channel},{"$inc":{"hilo":1}})
|
|
elif value >= 10:
|
|
self.bot.database["hilo"].update_one({"_id":channel},{"$inc":{"hilo":-1}})
|
|
|
|
return drawnCard
|
|
|
|
# Dealer draws a card and checks if they should draw another one
|
|
def dealerDraw(self,channel):
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
done = False
|
|
dealerHand = game["dealer hand"]
|
|
|
|
if self.calcHandValue(dealerHand) < 17:
|
|
dealerHand.append(self.drawCard(channel))
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},{"$set":{"dealer hand":dealerHand}})
|
|
else:
|
|
done = True
|
|
|
|
if self.calcHandValue(dealerHand) > 21:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},{"$set":{"dealer busted":True}})
|
|
|
|
return done
|
|
|
|
# Goes to the next round and calculates some stuff
|
|
def blackjackContinue(self, channel):
|
|
self.bot.log("Continuing blackjack game")
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
done = False
|
|
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},{"$inc":{"round":1}})
|
|
|
|
allStanding = True
|
|
preAllStanding = True
|
|
message = "All players are standing. The dealer now shows his cards and draws."
|
|
|
|
if game["all standing"]:
|
|
self.bot.log("All are standing")
|
|
|
|
done = self.dealerDraw(channel)
|
|
message = "The dealer draws a card."
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
self.bot.log("Testing if all are standing")
|
|
for user in game["user hands"]:
|
|
try:
|
|
newUser, allStanding, preAllStanding = self.testIfStanding(game["user hands"][user],allStanding,preAllStanding,True)
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},{"$set":{"user hands."+user:newUser}})
|
|
except:
|
|
self.bot.log("Error in testing if all are standing (error code 1331)")
|
|
|
|
if allStanding:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},{"$set":{"all standing":True}})
|
|
|
|
try:
|
|
self.draw.drawImage(channel)
|
|
except:
|
|
self.bot.log("Error drawing blackjack table (error code 1340)")
|
|
|
|
if allStanding:
|
|
if done == False:
|
|
return message, True, done
|
|
else:
|
|
return "The dealer is done drawing cards", True, done
|
|
elif preAllStanding:
|
|
return "", True, done
|
|
else:
|
|
if game["round"] == 1:
|
|
firstRoundMessage = ". You can also double down with \"/blackjack double\" or split with \"/blackjack split\""
|
|
else:
|
|
firstRoundMessage = ""
|
|
return "You have 2 minutes to either hit or stand with \"/blackjack hit\" or \"/blackjack stand\""+firstRoundMessage+". It's assumed you're standing if you don't make a choice.", False, done
|
|
|
|
def testIfStanding(self, hand,allStanding,preAllStanding,topLevel):
|
|
if hand["hit"] == False:
|
|
hand["standing"] = True
|
|
|
|
if hand["standing"] == False:
|
|
allStanding = False
|
|
|
|
if self.calcHandValue(hand["hand"]) >= 21 or hand["doubled"]:
|
|
hand["standing"] = True
|
|
else:
|
|
preAllStanding = False
|
|
|
|
hand["hit"] = False
|
|
|
|
if topLevel:
|
|
if hand["split"] >= 1:
|
|
hand["other hand"], allStanding, preAllStanding = self.testIfStanding(hand["other hand"],allStanding,preAllStanding,False)
|
|
if hand["split"] >= 2:
|
|
hand["third hand"], allStanding, preAllStanding = self.testIfStanding(hand["third hand"],allStanding,preAllStanding,False)
|
|
if hand["split"] >= 3:
|
|
hand["fourth hand"], allStanding, preAllStanding = self.testIfStanding(hand["fourth hand"],allStanding,preAllStanding,False)
|
|
|
|
return hand, allStanding, preAllStanding
|
|
|
|
# When players try to hit
|
|
async def hit(self, ctx, handNumber = 0):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
user = f"#{ctx.author.id}"
|
|
roundDone = False
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
if user in game["user hands"]:
|
|
|
|
userHands = game["user hands"][user]
|
|
hand, handNumber = self.getHandNumber(userHands, handNumber)
|
|
|
|
if hand == None:
|
|
logMessage = "They didn't specify a hand"
|
|
sendMessage = "You need to specify a hand"
|
|
elif game["round"] <= 0:
|
|
logMessage = "They tried to hit on the 0th round"
|
|
sendMessage = "You can't hit before you see your cards"
|
|
elif hand["hit"]:
|
|
logMessage = "They've already hit this round"
|
|
sendMessage = "You've already hit this round"
|
|
elif hand["standing"]:
|
|
logMessage = "They're already standing"
|
|
sendMessage = "You can't hit when you're standing"
|
|
else:
|
|
hand["hand"].append(self.drawCard(channel))
|
|
hand["hit"] = True
|
|
|
|
handValue = self.calcHandValue(hand["hand"])
|
|
|
|
if handValue > 21:
|
|
hand["busted"] = True
|
|
|
|
if handNumber == 2:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".other hand":hand}})
|
|
elif handNumber == 3:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".third hand":hand}})
|
|
elif handNumber == 4:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".fourth hand":hand}})
|
|
else:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user:hand}})
|
|
|
|
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
|
|
|
|
sendMessage = f"{ctx.author.display_name} hit"
|
|
logMessage = "They succeeded"
|
|
else:
|
|
logMessage = "They tried to hit without being in the game"
|
|
sendMessage = "You have to enter the game before you can hit"
|
|
|
|
await ctx.send(sendMessage)
|
|
self.bot.log(logMessage)
|
|
|
|
if roundDone:
|
|
gameID = game["gameID"]
|
|
self.bot.log("Hit calling self.blackjackLoop()", channel)
|
|
await self.blackjackLoop(ctx.channel, game["round"]+1, gameID)
|
|
|
|
# When players try to double down
|
|
async def double(self, ctx, handNumber = 0):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
user = f"#{ctx.author.id}"
|
|
roundDone = False
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
if user in game["user hands"]:
|
|
hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber)
|
|
|
|
if hand == None:
|
|
logMessage = "They didn't specify a hand"
|
|
sendMessage = "You need to specify a hand"
|
|
elif game["round"] <= 0:
|
|
logMessage = "They tried to hit on the 0th round"
|
|
sendMessage = "You can't hit before you see your cards"
|
|
elif hand["hit"]:
|
|
logMessage = "They've already hit this round"
|
|
sendMessage = "You've already hit this round"
|
|
elif hand["standing"]:
|
|
logMessage = "They're already standing"
|
|
sendMessage = "You can't hit when you're standing"
|
|
elif len(hand["hand"]) != 2:
|
|
logMessage = "They tried to double after round 1"
|
|
sendMessage = "You can only double on the first round"
|
|
else:
|
|
bet = hand["bet"]
|
|
if self.bot.money.checkBalance(user) < bet:
|
|
logMessage = "They tried to double without being in the game"
|
|
sendMessage = "You can't double when you're not in the game"
|
|
else:
|
|
self.bot.money.addMoney(user,-1 * bet)
|
|
|
|
hand["hand"].append(self.drawCard(channel))
|
|
hand["hit"] = True
|
|
hand["doubled"] = True
|
|
hand["bet"] += bet
|
|
|
|
handValue = self.calcHandValue(hand["hand"])
|
|
|
|
|
|
if handValue > 21:
|
|
hand["busted"] = True
|
|
|
|
if handNumber == 2:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".other hand":hand}})
|
|
elif handNumber == 3:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".third hand":hand}})
|
|
elif handNumber == 4:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".fourth hand":hand}})
|
|
else:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user:hand}})
|
|
|
|
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
|
|
|
|
sendMessage = f"Adding another {bet} GwendoBucks to {self.bot.databaseFuncs.getName(user)}'s bet and drawing another card."
|
|
logMessage = "They succeeded"
|
|
else:
|
|
logMessage = "They tried to double without being in the game"
|
|
sendMessage = "You can't double when you're not in the game"
|
|
|
|
await ctx.send(sendMessage)
|
|
self.bot.log(logMessage)
|
|
|
|
if roundDone:
|
|
gameID = game["gameID"]
|
|
self.bot.log("Double calling self.blackjackLoop()", channel)
|
|
await self.blackjackLoop(ctx.channel, game["round"]+1, gameID)
|
|
|
|
# When players try to stand
|
|
async def stand(self, ctx, handNumber = 0):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
user = f"#{ctx.author.id}"
|
|
roundDone = False
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
if user in game["user hands"]:
|
|
|
|
hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber)
|
|
|
|
if hand == None:
|
|
sendMessage = "You need to specify which hand"
|
|
logMessage = "They didn't specify a hand"
|
|
elif game["round"] <= 0:
|
|
sendMessage = "You can't stand before you see your cards"
|
|
logMessage = "They tried to stand on round 0"
|
|
elif hand["hit"]:
|
|
sendMessage = "You've already hit this round"
|
|
logMessage = "They'd already hit this round"
|
|
elif hand["standing"]:
|
|
sendMessage = "You're already standing"
|
|
logMessage = "They're already standing"
|
|
else:
|
|
hand["standing"] = True
|
|
|
|
if handNumber == 2:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".other hand":hand}})
|
|
elif handNumber == 3:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".third hand":hand}})
|
|
elif handNumber == 4:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".fourth hand":hand}})
|
|
else:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user:hand}})
|
|
|
|
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
|
|
|
|
sendMessage = f"{ctx.author.display_name} is standing"
|
|
logMessage = "They succeeded"
|
|
|
|
else:
|
|
logMessage = "They tried to stand without being in the game"
|
|
sendMessage = "You have to enter the game before you can stand"
|
|
|
|
await ctx.send(sendMessage)
|
|
self.bot.log(logMessage)
|
|
|
|
if roundDone:
|
|
gameID = game["gameID"]
|
|
self.bot.log("Stand calling self.blackjackLoop()", channel)
|
|
await self.blackjackLoop(ctx.channel, game["round"]+1, gameID)
|
|
|
|
# When players try to split
|
|
async def split(self, ctx, handNumber = 0):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
user = f"#{ctx.author.id}"
|
|
roundDone = False
|
|
handNumberError = False
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
if game["user hands"][user]["split"] == 0:
|
|
hand = game["user hands"][user]
|
|
newHand = game["user hands"][user]["other hand"]
|
|
handNumber = 0
|
|
otherHand = 2
|
|
else:
|
|
if handNumber == 1:
|
|
hand = game["user hands"][user]
|
|
elif handNumber == 2:
|
|
hand = game["user hands"][user]["other hand"]
|
|
elif handNumber == 3:
|
|
hand = game["user hands"][user]["third hand"]
|
|
else:
|
|
handNumberError = True
|
|
|
|
if game["user hands"][user]["split"] == 1:
|
|
newHand = game["user hands"][user]["third hand"]
|
|
otherHand = 3
|
|
else:
|
|
newHand = game["user hands"][user]["fourth hand"]
|
|
otherHand = 4
|
|
|
|
if handNumberError:
|
|
logMessage = "They didn't specify a hand"
|
|
sendMessage = "You have to specify the hand you're hitting with"
|
|
elif game["round"] == 0:
|
|
logMessage = "They tried to split on round 0"
|
|
sendMessage = "You can't split before you see your cards"
|
|
elif game["user hands"][user]["split"] > 3:
|
|
logMessage = "They tried to split more than three times"
|
|
sendMessage = "You can only split 3 times"
|
|
elif hand["hit"]:
|
|
logMessage = "They've already hit"
|
|
sendMessage = "You've already hit"
|
|
elif hand["standing"]:
|
|
logMessage = "They're already standing"
|
|
sendMessage = "You're already standing"
|
|
elif len(hand["hand"]) != 2:
|
|
logMessage = "They tried to split after the first round"
|
|
sendMessage = "You can only split on the first round"
|
|
else:
|
|
firstCard = self.calcHandValue([hand["hand"][0]])
|
|
secondCard = self.calcHandValue([hand["hand"][1]])
|
|
if firstCard != secondCard:
|
|
logMessage = "They tried to split two different cards"
|
|
sendMessage = "You can only split if your cards have the same value"
|
|
else:
|
|
bet = hand["bet"]
|
|
if self.bot.money.checkBalance(user) < bet:
|
|
logMessage = "They didn't have enough GwendoBucks"
|
|
sendMessage = "You don't have enough GwendoBucks"
|
|
else:
|
|
self.bot.money.addMoney(user,-1 * bet)
|
|
|
|
hand["hit"] = True
|
|
newHand["hit"] = True
|
|
|
|
newHand = {
|
|
"hand":[],"bet":0,"standing":False,"busted":False,
|
|
"blackjack":False,"hit":True,"doubled":False}
|
|
|
|
newHand["bet"] = hand["bet"]
|
|
|
|
newHand["hand"].append(hand["hand"].pop(1))
|
|
newHand["hand"].append(self.drawCard(channel))
|
|
hand["hand"].append(self.drawCard(channel))
|
|
|
|
handValue = self.calcHandValue(hand["hand"])
|
|
otherHandValue = self.calcHandValue(newHand["hand"])
|
|
if handValue > 21:
|
|
hand["busted"] = True
|
|
elif handValue == 21:
|
|
hand["blackjack"] = True
|
|
|
|
if otherHandValue > 21:
|
|
newHand["busted"] = True
|
|
elif otherHandValue == 21:
|
|
newHand["blackjack"] = True
|
|
|
|
if handNumber == 2:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".other hand":hand}})
|
|
elif handNumber == 3:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".third hand":hand}})
|
|
else:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user:hand}})
|
|
|
|
if otherHand == 3:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".third hand":newHand}})
|
|
elif otherHand == 4:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".fourth hand":newHand}})
|
|
else:
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$set":{"user hands."+user+".other hand":newHand}})
|
|
|
|
self.bot.database["blackjack games"].update_one({"_id":channel},
|
|
{"$inc":{"user hands."+user+".split":1}})
|
|
|
|
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
|
|
|
|
sendMessage = f"Splitting {self.bot.databaseFuncs.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."
|
|
logMessage = "They succeeded"
|
|
|
|
await ctx.send(sendMessage)
|
|
self.bot.log(logMessage)
|
|
|
|
if roundDone:
|
|
gameID = game["gameID"]
|
|
self.bot.log("Stand calling self.blackjackLoop()", channel)
|
|
await self.blackjackLoop(ctx.channel, game["round"]+1, gameID)
|
|
|
|
# Player enters the game and draws a hand
|
|
async def playerDrawHand(self, ctx, bet : int):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
user = f"#{ctx.author.id}"
|
|
collection = self.bot.database["blackjack games"]
|
|
game = collection.find_one({"_id":channel})
|
|
userName = self.bot.databaseFuncs.getName(user)
|
|
|
|
self.bot.log(f"{userName} is trying to join the Blackjack game")
|
|
|
|
if game == None:
|
|
sendMessage = "There is no game going on in this channel"
|
|
logMessage = sendMessage
|
|
elif user in game["user hands"]:
|
|
sendMessage = "You're already in the game!"
|
|
logMessage = "They're already in the game"
|
|
elif len(game["user hands"]) >= 5:
|
|
sendMessage = "There can't be more than 5 players in a game"
|
|
logMessage = "There were already 5 players in the game"
|
|
elif game["round"] != 0:
|
|
sendMessage = "The table is no longer taking bets"
|
|
logMessage = "They tried to join after the game begun"
|
|
elif bet < 0:
|
|
sendMessage = "You can't bet a negative amount"
|
|
logMessage = "They tried to bet a negative amount"
|
|
elif self.bot.money.checkBalance(user) < bet:
|
|
sendMessage = "You don't have enough GwendoBucks"
|
|
logMessage = "They didn't have enough GwendoBucks"
|
|
else:
|
|
self.bot.money.addMoney(user,-1 * bet)
|
|
playerHand = [self.drawCard(channel) for _ in range(2)]
|
|
|
|
handValue = self.calcHandValue(playerHand)
|
|
|
|
if handValue == 21:
|
|
blackjackHand = True
|
|
else:
|
|
blackjackHand = False
|
|
|
|
newHand = {"hand":playerHand, "bet":bet, "standing":False,
|
|
"busted":False, "blackjack":blackjackHand, "hit":True,
|
|
"doubled":False, "split":0, "other hand":{},
|
|
"third hand":{}, "fourth hand":{}}
|
|
|
|
function = {"$set":{f"user hands.{user}":newHand}}
|
|
collection.update_one({"_id":channel}, function)
|
|
|
|
enterGameText = "entered the game with a bet of"
|
|
betText = f"{bet} GwendoBucks"
|
|
sendMessage = f"{userName} {enterGameText} {betText}"
|
|
logMessage = sendMessage
|
|
|
|
self.bot.log(sendMessage)
|
|
await ctx.send(logMessage)
|
|
|
|
# Starts a game of blackjack
|
|
async def start(self, ctx):
|
|
await self.bot.defer(ctx)
|
|
channel = str(ctx.channel_id)
|
|
blackjackMinCards = 50
|
|
blackjackDecks = 4
|
|
|
|
await ctx.send("Starting a new game of blackjack")
|
|
cardsLeft = 0
|
|
cards = self.bot.database["blackjack cards"].find_one({"_id":channel})
|
|
if cards != None:
|
|
cardsLeft = len(cards["cards"])
|
|
|
|
# Shuffles if not enough cards
|
|
if cardsLeft < blackjackMinCards:
|
|
self.blackjackShuffle(blackjackDecks, channel)
|
|
self.bot.log("Shuffling the blackjack deck...", channel)
|
|
await ctx.channel.send("Shuffling the deck...")
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
self.bot.log("Trying to start a blackjack game in "+channel)
|
|
gameStarted = False
|
|
|
|
if game == None:
|
|
|
|
dealerHand = [self.drawCard(channel),self.drawCard(channel)]
|
|
gameID = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
|
|
|
newGame = {"_id":channel,"dealer hand": dealerHand,"dealer busted":False,"dealer blackjack":False,"user hands": {},"all standing":False,"round":0,"gameID":gameID}
|
|
|
|
if self.calcHandValue(dealerHand) == 21:
|
|
newGame["dealer blackjack"] = True
|
|
|
|
self.bot.database["blackjack games"].insert_one(newGame)
|
|
|
|
copyfile("resources/games/blackjackTable.png","resources/games/blackjackTables/blackjackTable"+channel+".png")
|
|
|
|
gameStarted = True
|
|
|
|
if gameStarted:
|
|
sendMessage = "Blackjack game started. Use \"/blackjack bet [amount]\" to enter the game within the next 30 seconds."
|
|
await ctx.channel.send(sendMessage)
|
|
filePath = f"resources/games/blackjackTables/blackjackTable{channel}.png"
|
|
|
|
oldImage = await ctx.channel.send(file = discord.File(filePath))
|
|
|
|
with open("resources/games/oldImages/blackjack"+channel, "w") as f:
|
|
f.write(str(oldImage.id))
|
|
|
|
await asyncio.sleep(30)
|
|
|
|
gamedone = False
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":str(channel)})
|
|
|
|
if len(game["user hands"]) == 0:
|
|
gamedone = True
|
|
await ctx.channel.send("No one entered the game. Ending the game.")
|
|
gameID = game["gameID"]
|
|
|
|
# Loop of game rounds
|
|
if gamedone == False:
|
|
self.bot.log("start() calling blackjackLoop()", channel)
|
|
await self.blackjackLoop(ctx.channel,1,gameID)
|
|
else:
|
|
new_message = self.blackjackFinish(channel)
|
|
await ctx.channel.send(new_message)
|
|
else:
|
|
await ctx.channel.send("There's already a blackjack game going on. Try again in a few minutes.")
|
|
self.bot.log("There was already a game going on")
|
|
|
|
# Ends the game and calculates winnings
|
|
def blackjackFinish(self,channel):
|
|
finalWinnings = "*Final Winnings:*\n"
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
dealerValue = self.calcHandValue(game["dealer hand"])
|
|
dealerBlackjack = game["dealer blackjack"]
|
|
dealerBusted = game["dealer busted"]
|
|
|
|
try:
|
|
for user in game["user hands"]:
|
|
|
|
winnings, netWinnings, reason = self.calcWinnings(game["user hands"][user],dealerValue,True,dealerBlackjack,dealerBusted)
|
|
|
|
if winnings < 0:
|
|
if winnings == -1:
|
|
finalWinnings += self.bot.databaseFuncs.getName(user)+" lost "+str(-1 * winnings)+" GwendoBuck "+reason+"\n"
|
|
else:
|
|
finalWinnings += self.bot.databaseFuncs.getName(user)+" lost "+str(-1 * winnings)+" GwendoBucks "+reason+"\n"
|
|
else:
|
|
if winnings == 1:
|
|
finalWinnings += self.bot.databaseFuncs.getName(user)+" won "+str(winnings)+" GwendoBuck "+reason+"\n"
|
|
else:
|
|
finalWinnings += self.bot.databaseFuncs.getName(user)+" won "+str(winnings)+" GwendoBucks "+reason+"\n"
|
|
|
|
self.bot.money.addMoney(user,netWinnings)
|
|
|
|
except:
|
|
self.bot.log("Error calculating winnings (error code 1311)")
|
|
|
|
self.bot.database["blackjack games"].delete_one({"_id":channel})
|
|
|
|
return finalWinnings
|
|
|
|
def calcWinnings(self,hand, dealerValue, topLevel, dealerBlackjack, dealerBusted):
|
|
self.bot.log("Calculating winnings")
|
|
reason = ""
|
|
bet = hand["bet"]
|
|
winnings = -1 * bet
|
|
netWinnings = 0
|
|
handValue = self.calcHandValue(hand["hand"])
|
|
|
|
if hand["blackjack"] and dealerBlackjack == False:
|
|
reason += "(blackjack)"
|
|
winnings += math.floor(2.5 * bet)
|
|
netWinnings += math.floor(2.5 * bet)
|
|
elif dealerBlackjack:
|
|
reason += "(dealer blackjack)"
|
|
elif hand["busted"]:
|
|
reason += "(busted)"
|
|
else:
|
|
if dealerBusted:
|
|
reason = "(dealer busted)"
|
|
winnings += 2 * bet
|
|
netWinnings += 2 * bet
|
|
elif handValue > dealerValue:
|
|
winnings += 2 * bet
|
|
netWinnings += 2 * bet
|
|
reason = "(highest value)"
|
|
elif handValue == dealerValue:
|
|
reason = "(pushed)"
|
|
winnings += bet
|
|
netWinnings += bet
|
|
else:
|
|
reason = "(highest value)"
|
|
|
|
if topLevel:
|
|
if hand["split"] >= 1:
|
|
winningsTemp, netWinningsTemp, reasonTemp = self.calcWinnings(hand["other hand"],dealerValue,False,dealerBlackjack,dealerBusted)
|
|
winnings += winningsTemp
|
|
netWinnings += netWinningsTemp
|
|
reason += reasonTemp
|
|
if hand["split"] >= 2:
|
|
winningsTemp, netWinningsTemp, reasonTemp = self.calcWinnings(hand["third hand"],dealerValue,False,dealerBlackjack,dealerBusted)
|
|
winnings += winningsTemp
|
|
netWinnings += netWinningsTemp
|
|
reason += reasonTemp
|
|
if hand["split"] >= 3:
|
|
winningsTemp, netWinningsTemp, reasonTemp = self.calcWinnings(hand["fourth hand"],dealerValue,False,dealerBlackjack,dealerBusted)
|
|
winnings += winningsTemp
|
|
netWinnings += netWinningsTemp
|
|
reason += reasonTemp
|
|
|
|
return winnings, netWinnings, reason
|
|
|
|
def getHandNumber(self, 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:
|
|
self.bot.log("Problem with getHandNumber() (error code 1322)")
|
|
|
|
def isRoundDone(self,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
|
|
|
|
# Loop of blackjack game rounds
|
|
async def blackjackLoop(self,channel,gameRound,gameID):
|
|
self.bot.log("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 = self.blackjackContinue(str(channel.id))
|
|
if new_message != "":
|
|
self.bot.log(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:
|
|
self.bot.log("Loop "+str(gameRound)+" interrupted (error code 1321)")
|
|
|
|
game = self.bot.database["blackjack games"].find_one({"_id":str(channel.id)})
|
|
|
|
if game != None:
|
|
realRound = game["round"]
|
|
realGameID = game["gameID"]
|
|
|
|
if gameRound == realRound and realGameID == gameID:
|
|
if gamedone == False:
|
|
self.bot.log("Loop "+str(gameRound)+" calling self.blackjackLoop()",str(channel.id))
|
|
await self.blackjackLoop(channel,gameRound+1,gameID)
|
|
else:
|
|
try:
|
|
new_message = self.blackjackFinish(str(channel.id))
|
|
except:
|
|
self.bot.log("Something fucked up (error code 1310)")
|
|
await channel.send(new_message)
|
|
else:
|
|
self.bot.log("Ending loop on round "+str(gameRound),str(channel.id))
|
|
else:
|
|
self.bot.log("Ending loop on round "+str(gameRound),str(channel.id))
|
|
|
|
# Returning current hi-lo value
|
|
async def hilo(self, ctx):
|
|
channel = ctx.channel_id
|
|
data = self.bot.database["hilo"].find_one({"_id":str(channel)})
|
|
if data != None:
|
|
hilo = str(data["hilo"])
|
|
else:
|
|
hilo = "0"
|
|
await ctx.send(f"Hi-lo value: {hilo}", hidden=True)
|
|
|
|
# Shuffles the blackjack deck
|
|
async def shuffle(self, ctx):
|
|
blackjackDecks = 4
|
|
channel = ctx.channel_id
|
|
self.blackjackShuffle(blackjackDecks,str(channel))
|
|
self.bot.log("Shuffling the blackjack deck...",str(channel))
|
|
await ctx.send("Shuffling the deck...")
|
|
|
|
|
|
# Tells you the amount of cards left
|
|
async def cards(self, ctx):
|
|
channel = ctx.channel_id
|
|
cardsLeft = 0
|
|
cards = self.bot.database["blackjack cards"].find_one({"_id":str(channel)})
|
|
if cards != None:
|
|
cardsLeft = len(cards["cards"])
|
|
|
|
decksLeft = round(cardsLeft/52,1)
|
|
await ctx.send(f"Cards left:\n{cardsLeft} cards, {decksLeft} decks", hidden=True)
|
|
|
|
class DrawBlackjack():
|
|
def __init__(self,bot):
|
|
self.bot = bot
|
|
self.BORDER = 100
|
|
self.PLACEMENT = [0,0]
|
|
self.ROTATION = 0
|
|
|
|
def drawImage(self,channel):
|
|
self.bot.log("Drawing blackjack table",channel)
|
|
game = self.bot.database["blackjack games"].find_one({"_id":channel})
|
|
|
|
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 50)
|
|
fntSmol = ImageFont.truetype('resources/fonts/futura-bold.ttf', 40)
|
|
self.BORDERSmol = int(self.BORDER/3.5)
|
|
|
|
table = Image.open("resources/games/blackjackTable.png")
|
|
self.PLACEMENT = [2,1,3,0,4]
|
|
textImage = ImageDraw.Draw(table)
|
|
hands = game["user hands"]
|
|
|
|
dealerBusted = game["dealer busted"]
|
|
dealerBlackjack = game["dealer blackjack"]
|
|
|
|
try:
|
|
if game["all standing"] == False:
|
|
dealerHand = self.drawHand(game["dealer hand"],True,False,False)
|
|
else:
|
|
dealerHand = self.drawHand(game["dealer hand"],False,dealerBusted,dealerBlackjack)
|
|
except:
|
|
self.bot.log("Error drawing dealer hand (error code 1341a)")
|
|
|
|
table.paste(dealerHand,(800-self.BORDERSmol,20-self.BORDERSmol),dealerHand)
|
|
|
|
for x in range(len(hands)):
|
|
key, value = list(hands.items())[x]
|
|
key = self.bot.databaseFuncs.getName(key)
|
|
#self.bot.log("Drawing "+key+"'s hand")
|
|
userHand = self.drawHand(value["hand"],False,value["busted"],value["blackjack"])
|
|
try:
|
|
if value["split"] == 3:
|
|
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),280-self.BORDERSmol),userHand)
|
|
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
|
|
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),420-self.BORDERSmol),userOtherHand)
|
|
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
|
|
table.paste(userThirdHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userThirdHand)
|
|
userFourthHand = self.drawHand(value["fourth hand"]["hand"],False,value["fourth hand"]["busted"],value["fourth hand"]["blackjack"])
|
|
table.paste(userFourthHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userFourthHand)
|
|
elif value["split"] == 2:
|
|
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),420-self.BORDERSmol),userHand)
|
|
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
|
|
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userOtherHand)
|
|
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
|
|
table.paste(userThirdHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userThirdHand)
|
|
elif value["split"] == 1:
|
|
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userHand)
|
|
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
|
|
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userOtherHand)
|
|
else:
|
|
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),680-self.BORDERSmol),userHand)
|
|
except:
|
|
self.bot.log("Error drawing player hands (error code 1341b)")
|
|
|
|
textWidth = fnt.getsize(key)[0]
|
|
if textWidth < 360:
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-3,1010-3),key,fill=(0,0,0), font=fnt)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+3,1010-3),key,fill=(0,0,0), font=fnt)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-3,1010+3),key,fill=(0,0,0), font=fnt)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+3,1010+3),key,fill=(0,0,0), font=fnt)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2),1005),key,fill=(255,255,255), font=fnt)
|
|
else:
|
|
textWidth = fntSmol.getsize(key)[0]
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-2,1020-2),key,fill=(0,0,0), font=fntSmol)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+2,1020-2),key,fill=(0,0,0), font=fntSmol)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-2,1020+2),key,fill=(0,0,0), font=fntSmol)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+2,1020+2),key,fill=(0,0,0), font=fntSmol)
|
|
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2),1015),key,fill=(255,255,255), font=fntSmol)
|
|
|
|
self.bot.log("Saving table image")
|
|
table.save("resources/games/blackjackTables/blackjackTable"+channel+".png")
|
|
|
|
return
|
|
|
|
def drawHand(self, hand, dealer, busted, blackjack):
|
|
self.bot.log("Drawing hand "+str(hand)+", "+str(busted)+", "+str(blackjack))
|
|
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 200)
|
|
fnt2 = ImageFont.truetype('resources/fonts/futura-bold.ttf', 120)
|
|
length = len(hand)
|
|
background = Image.new("RGBA", ((self.BORDER*2)+691+(125*(length-1)),(self.BORDER*2)+1065),(0,0,0,0))
|
|
textImage = ImageDraw.Draw(background)
|
|
|
|
if dealer:
|
|
img = Image.open("resources/games/cards/"+hand[0].upper()+".png")
|
|
#self.ROTATION = (random.randint(-20,20)/10.0)
|
|
img = img.rotate(self.ROTATION,expand = 1)
|
|
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
|
|
background.paste(img,(self.BORDER+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
|
|
img = Image.open("resources/games/cards/red_back.png")
|
|
#self.ROTATION = (random.randint(-20,20)/10.0)
|
|
img = img.rotate(self.ROTATION,expand = 1)
|
|
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
|
|
background.paste(img,(125+self.BORDER+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
|
|
else:
|
|
for x in range(length):
|
|
img = Image.open("resources/games/cards/"+hand[x].upper()+".png")
|
|
#self.ROTATION = (random.randint(-20,20)/10.0)
|
|
img = img.rotate(self.ROTATION,expand = 1)
|
|
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
|
|
background.paste(img,(self.BORDER+(x*125)+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
|
|
|
|
w, h = background.size
|
|
textHeight = 290+self.BORDER
|
|
|
|
#self.bot.log("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)
|
|
|
|
#self.bot.log("Returning resized image")
|
|
return background.resize((int(w/3.5),int(h/3.5)),resample=Image.BILINEAR)
|
|
|