Merge pull request #64 from NikolajDanger/improve_codebase

Improve cogs and better slash command integration
This commit is contained in:
NikolajDanger
2021-04-06 15:16:00 +02:00
committed by GitHub
33 changed files with 1668 additions and 1546 deletions

View File

@ -4,7 +4,7 @@ from discord.ext import commands
from discord_slash import SlashCommand from discord_slash import SlashCommand
from pymongo import MongoClient from pymongo import MongoClient
from funcs import Money, StarWars, Games, Other, LookupFuncs from funcs import Money, StarWars, Games, Other, LookupFuncs
from utils import Options, Credentials, logThis, makeFiles, databaseFuncs from utils import Options, Credentials, logThis, makeFiles, databaseFuncs, EventHandler, ErrorHandler
class Gwendolyn(commands.Bot): class Gwendolyn(commands.Bot):
def __init__(self): def __init__(self):
@ -25,6 +25,8 @@ class Gwendolyn(commands.Bot):
self.games = Games(self) self.games = Games(self)
self.money = Money(self) self.money = Money(self)
self.databaseFuncs = databaseFuncs(self) self.databaseFuncs = databaseFuncs(self)
self.eventHandler = EventHandler(self)
self.errorHandler = ErrorHandler(self)
intents = discord.Intents.default() intents = discord.Intents.default()
intents.members = True intents.members = True
@ -34,6 +36,20 @@ class Gwendolyn(commands.Bot):
def log(self, messages, channel : str = "", level : int = 20): def log(self, messages, channel : str = "", level : int = 20):
logThis(messages, channel, level) logThis(messages, channel, level)
async def stop(self, ctx):
if f"#{ctx.author.id}" in self.options.admins:
await ctx.send("Pulling git repo and restarting...")
await self.change_presence(status = discord.Status.offline)
self.databaseFuncs.stopServer()
self.log("Logging out", level = 25)
await self.close()
else:
self.log(f"{ctx.author.display_name} tried to stop me! (error code 201)",str(ctx.channel_id))
await ctx.send(f"I don't think I will, {ctx.author.display_name} (error code 201)")
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,57 +1,34 @@
import discord, traceback
from discord.ext import commands from discord.ext import commands
class EventCog(commands.Cog): class EventCog(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.bot.on_error = self.on_error
# Syncs commands, sets the game, and logs when the bot logs in # Syncs commands, sets the game, and logs when the bot logs in
@commands.Cog.listener() @commands.Cog.listener()
async def on_ready(self): async def on_ready(self):
await self.bot.databaseFuncs.syncCommands() await self.bot.eventHandler.on_ready()
self.bot.log("Logged in as "+self.bot.user.name+", "+str(self.bot.user.id), level = 25)
game = discord.Game("Use /help for commands")
await self.bot.change_presence(activity=game, status = discord.Status.online)
@commands.Cog.listener()
async def on_disconnect(self):
await self.bot.change_presence(status = discord.Status.offline)
# Logs when user sends a command # Logs when user sends a command
@commands.Cog.listener() @commands.Cog.listener()
async def on_slash_command(self, ctx): async def on_slash_command(self, ctx):
self.bot.log(f"{ctx.author.display_name} ran /{ctx.name}", str(ctx.channel_id), level = 25) await self.bot.eventHandler.on_slash_command(ctx)
# Logs if a command experiences an error # Logs if a command experiences an error
@commands.Cog.listener() @commands.Cog.listener()
async def on_slash_command_error(self, ctx, error): async def on_slash_command_error(self, ctx, error):
if isinstance(error, commands.CommandNotFound): await self.bot.errorHandler.on_slash_command_error(ctx, error)
await ctx.send("That's not a command (error code 001)")
elif isinstance(error,commands.errors.MissingRequiredArgument):
self.bot.log(f"{error}",str(ctx.channel_id))
await ctx.send("Missing command parameters (error code 002). Try using `!help [command]` to find out how to use the command.")
else:
exception = traceback.format_exception(type(error), error, error.__traceback__)
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception) # Logs if on error occurs
self.bot.log([f"exception in /{ctx.name}", f"{exceptionString}"],str(ctx.channel_id), 40) async def on_error(self, method, *args, **kwargs):
await ctx.send("Something went wrong (error code 000)") await self.bot.errorHandler.on_error(method)
# Logs if an error occurs # If someone reacted to a message, checks if it's a reaction it's
# Gwendolyn has been waiting for, and then does something
@commands.Cog.listener() @commands.Cog.listener()
async def on_error(self, method): async def on_reaction_add(self, reaction, user):
exception = traceback.format_exc() await self.bot.eventHandler.on_reaction_add(reaction, user)
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{method}", f"{exceptionString}"], level = 40)
def setup(bot): def setup(bot):
bot.add_cog(EventCog(bot)) bot.add_cog(EventCog(bot))

View File

@ -1,7 +1,5 @@
import discord, asyncio, json
from discord.ext import commands from discord.ext import commands
from discord_slash import cog_ext from discord_slash import cog_ext
from discord_slash import SlashCommandOptionType as scot
from utils import getParams from utils import getParams
@ -15,73 +13,22 @@ class GamesCog(commands.Cog):
# Checks user balance # Checks user balance
@cog_ext.cog_slash(**params["balance"]) @cog_ext.cog_slash(**params["balance"])
async def balance(self, ctx): async def balance(self, ctx):
await ctx.defer() await self.bot.money.sendBalance(ctx)
response = self.bot.money.checkBalance("#"+str(ctx.author.id))
if response == 1:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBuck"
else:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBucks"
await ctx.send(new_message)
# Gives another user an amount of GwendoBucks # Gives another user an amount of GwendoBucks
@cog_ext.cog_slash(**params["give"]) @cog_ext.cog_slash(**params["give"])
async def give(self, ctx, user, amount): async def give(self, ctx, user, amount):
await ctx.defer() await self.bot.money.giveMoney(ctx, user, amount)
username = user.display_name
if self.bot.databaseFuncs.getID(username) == None:
async for member in ctx.guild.fetch_members(limit=None):
if member.display_name.lower() == username.lower():
username = member.display_name
userID = "#" + str(member.id)
self.bot.database["users"].insert_one({"_id":userID,"user name":username,"money":0})
response = self.bot.money.giveMoney("#"+str(ctx.author.id),username,amount)
await ctx.send(response)
# Invest GwendoBucks in the stock market # Invest GwendoBucks in the stock market
@cog_ext.cog_slash(**params["invest"]) @cog_ext.cog_slash(**params["invest"])
async def invest(self, ctx, parameters = "check"): async def invest(self, ctx, parameters = "check"):
await ctx.defer() await self.bot.games.invest.parseInvest(ctx, parameters)
response = self.bot.games.invest.parseInvest(parameters,"#"+str(ctx.author.id))
if response.startswith("**"):
responses = response.split("\n")
em = discord.Embed(title=responses[0],description="\n".join(responses[1:]),colour=0x00FF00)
await ctx.send(embed=em)
else:
await ctx.send(response)
# Runs a game of trivia # Runs a game of trivia
@cog_ext.cog_slash(**params["trivia"]) @cog_ext.cog_slash(**params["trivia"])
async def trivia(self, ctx, answer = ""): async def trivia(self, ctx, answer = ""):
await ctx.defer() await self.bot.games.trivia.triviaParse(ctx, answer)
if answer == "":
question, options, correctAnswer = self.bot.games.trivia.triviaStart(str(ctx.channel_id))
if options != "":
results = "**"+question+"**\n"
for x, option in enumerate(options):
results += chr(x+97) + ") "+option+"\n"
await ctx.send(results)
await asyncio.sleep(60)
self.bot.games.trivia.triviaCountPoints(str(ctx.channel_id))
self.bot.databaseFuncs.deleteGame("trivia questions",str(ctx.channel_id))
self.bot.log("Time's up for the trivia question",str(ctx.channel_id))
await ctx.send("Time's up The answer was \""+chr(correctAnswer)+") "+options[correctAnswer-97]+"\". Anyone who answered that has gotten 1 GwendoBuck")
else:
await ctx.send(question, hidden=True)
elif answer in ["a","b","c","d"]:
response = self.bot.games.trivia.triviaAnswer("#"+str(ctx.author.id),str(ctx.channel_id),answer)
if response.startswith("Locked in "):
await ctx.send(f"{ctx.author.display_name} answered {answer}")
else:
await ctx.send(response)
else:
self.bot.log("I didn't understand that (error code 1101)",str(ctx.channel_id))
await ctx.send("I didn't understand that (error code 1101)")
class BlackjackCog(commands.Cog): class BlackjackCog(commands.Cog):
@ -92,103 +39,113 @@ class BlackjackCog(commands.Cog):
# Starts a game of blackjack # Starts a game of blackjack
@cog_ext.cog_subcommand(**params["blackjackStart"]) @cog_ext.cog_subcommand(**params["blackjackStart"])
async def blackjackStart(self, ctx): async def blackjackStart(self, ctx):
await ctx.defer() await self.bot.games.blackjack.start(ctx)
await self.bot.games.blackjack.parseBlackjack("", ctx)
@cog_ext.cog_subcommand(**params["blackjackBet"]) @cog_ext.cog_subcommand(**params["blackjackBet"])
async def blackjackBet(self, ctx, bet): async def blackjackBet(self, ctx, bet):
await ctx.defer() await self.bot.games.blackjack.playerDrawHand(ctx, bet)
await self.bot.games.blackjack.parseBlackjack(f"bet {bet}", ctx)
@cog_ext.cog_subcommand(**params["blackjackStand"]) @cog_ext.cog_subcommand(**params["blackjackStand"])
async def blackjackStand(self, ctx, hand = ""): async def blackjackStand(self, ctx, hand = ""):
await ctx.defer() await self.bot.games.blackjack.stand(ctx, hand)
await self.bot.games.blackjack.parseBlackjack(f"stand {hand}", ctx)
@cog_ext.cog_subcommand(**params["blackjackHit"]) @cog_ext.cog_subcommand(**params["blackjackHit"])
async def blackjackHit(self, ctx, hand = ""): async def blackjackHit(self, ctx, hand = 0):
await ctx.defer() await self.bot.games.blackjack.hit(ctx, hand)
await self.bot.games.blackjack.parseBlackjack(f"hit {hand}", ctx)
@cog_ext.cog_subcommand(**params["blackjackDouble"])
async def blackjackDouble(self, ctx, hand = 0):
await self.bot.games.blackjack.double(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjackSplit"])
async def blackjackSplit(self, ctx, hand = 0):
await self.bot.games.blackjack.split(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjackHilo"])
async def blackjackHilo(self, ctx):
await self.bot.games.blackjack.hilo(ctx)
@cog_ext.cog_subcommand(**params["blackjackShuffle"])
async def blackjackShuffle(self, ctx):
await self.bot.games.blackjack.shuffle(ctx)
@cog_ext.cog_subcommand(**params["blackjackCards"])
async def blackjackCards(self, ctx):
await self.bot.games.blackjack.cards(ctx)
class ConnectFourCog(commands.Cog): class ConnectFourCog(commands.Cog):
def __init__(self,bot): def __init__(self,bot):
"""Runs game stuff.""" """Runs game stuff."""
self.bot = bot self.bot = bot
# Start a game of connect four against a user # Start a game of connect four against a user
@cog_ext.cog_subcommand(**params["connectFourStartUser"]) @cog_ext.cog_subcommand(**params["connectFourStartUser"])
async def connectFourStartUser(self, ctx, user): async def connectFourStartUser(self, ctx, user):
await ctx.defer() await self.bot.games.connectFour.start(ctx, user)
await self.bot.games.gameLoops.connectFour(ctx, "start "+user.display_name)
# Start a game of connect four against gwendolyn # Start a game of connect four against gwendolyn
@cog_ext.cog_subcommand(**params["connectFourStartGwendolyn"]) @cog_ext.cog_subcommand(**params["connectFourStartGwendolyn"])
async def connectFourStartGwendolyn(self, ctx, difficulty = 3): async def connectFourStartGwendolyn(self, ctx, difficulty = 3):
await ctx.defer() await self.bot.games.connectFour.start(ctx, difficulty)
await self.bot.games.gameLoops.connectFour(ctx, "start "+str(difficulty))
# Stop the current game of connect four # Stop the current game of connect four
@cog_ext.cog_subcommand(**params["connectFourStop"]) @cog_ext.cog_subcommand(**params["connectFourSurrender"])
async def connectFourStop(self, ctx): async def connectFourSurrender(self, ctx):
await self.bot.games.gameLoops.connectFour(ctx, "stop") await self.bot.games.connectFour.surrender(ctx)
# Place a piece in the current game of connect four
@cog_ext.cog_subcommand(**params["connectFourPlace"])
async def connectFourPlace(self, ctx, column):
await self.bot.games.gameLoops.connectFour(ctx, "place "+str(column))
class HangmanCog(commands.Cog): class HangmanCog(commands.Cog):
def __init__(self,bot): def __init__(self,bot):
"""Runs game stuff.""" """Runs game stuff."""
self.bot = bot self.bot = bot
# Starts a game of Hangman # Starts a game of Hangman
@cog_ext.cog_subcommand(**params["hangmanStart"]) @cog_ext.cog_subcommand(**params["hangmanStart"])
async def hangmanStart(self, ctx): async def hangmanStart(self, ctx):
await ctx.defer() await self.bot.games.hangman.start(ctx)
await self.bot.games.gameLoops.runHangman(ctx.channel,"#"+str(ctx.author.id),"start", ctx)
# Stops a game of Hangman # Stops a game of Hangman
@cog_ext.cog_subcommand(**params["hangmanStop"]) @cog_ext.cog_subcommand(**params["hangmanStop"])
async def hangmanStop(self, ctx): async def hangmanStop(self, ctx):
await self.bot.games.gameLoops.runHangman(ctx.channel,"#"+str(ctx.author.id),"stop", ctx) await self.bot.games.hangman.stop(ctx)
class HexCog(commands.Cog): class HexCog(commands.Cog):
def __init__(self,bot): def __init__(self,bot):
"""Runs game stuff.""" """Runs game stuff."""
self.bot = bot self.bot = bot
# Start a game of Hex against another user # Start a game of Hex against another user
@cog_ext.cog_subcommand(**params["hexStartUser"]) @cog_ext.cog_subcommand(**params["hexStartUser"])
async def hexStartUser(self, ctx, user): async def hexStartUser(self, ctx, user):
await ctx.defer() await self.bot.games.hex.start(ctx, user)
await self.bot.games.gameLoops.runHex(ctx, "start "+user.display_name, "#"+str(ctx.author.id))
# Start a game of Hex against Gwendolyn # Start a game of Hex against Gwendolyn
@cog_ext.cog_subcommand(**params["hexStartGwendolyn"]) @cog_ext.cog_subcommand(**params["hexStartGwendolyn"])
async def hexStartGwendolyn(self, ctx, difficulty = 2): async def hexStartGwendolyn(self, ctx, difficulty = 2):
await ctx.defer() await self.bot.games.hex.start(ctx, difficulty)
await self.bot.games.gameLoops.runHex(ctx, "start "+str(difficulty), "#"+str(ctx.author.id))
# Undo your last hex move
@cog_ext.cog_subcommand(**params["hexUndo"])
async def hexUndo(self, ctx):
await self.bot.games.gameLoops.runHex(ctx, "undo", "#"+str(ctx.author.id))
# Perform a hex swap
@cog_ext.cog_subcommand(**params["hexSwap"])
async def hexSwap(self, ctx):
await self.bot.games.gameLoops.runHex(ctx, "swap", "#"+str(ctx.author.id))
# Surrender the hex game
@cog_ext.cog_subcommand(**params["hexSurrender"])
async def hexSurrender(self, ctx):
await self.bot.games.gameLoops.runHex(ctx, "surrender", "#"+str(ctx.author.id))
# Place a piece in the hex game # Place a piece in the hex game
@cog_ext.cog_subcommand(**params["hexPlace"]) @cog_ext.cog_subcommand(**params["hexPlace"])
async def hexPlace(self, ctx, coordinates): async def hexPlace(self, ctx, coordinates):
await self.bot.games.gameLoops.runHex(ctx, "place "+coordinates, "#"+str(ctx.author.id)) await self.bot.games.hex.placeHex(ctx, coordinates, f"#{ctx.author.id}")
# Undo your last hex move
@cog_ext.cog_subcommand(**params["hexUndo"])
async def hexUndo(self, ctx):
await self.bot.games.hex.undo(ctx)
# Perform a hex swap
@cog_ext.cog_subcommand(**params["hexSwap"])
async def hexSwap(self, ctx):
await self.bot.games.hex.swap(ctx)
# Surrender the hex game
@cog_ext.cog_subcommand(**params["hexSurrender"])
async def hexSurrender(self, ctx):
await self.bot.games.hex.surrender(ctx)
def setup(bot): def setup(bot):
bot.add_cog(GamesCog(bot)) bot.add_cog(GamesCog(bot))

View File

@ -1,9 +1,7 @@
import discord, json
from discord.ext import commands from discord.ext import commands
from discord_slash import cog_ext from discord_slash import cog_ext
from discord_slash import SlashCommandOptionType as scot
from utils import getParams, cap from utils import getParams
params = getParams() params = getParams()
@ -15,58 +13,12 @@ class LookupCog(commands.Cog):
# Looks up a spell # Looks up a spell
@cog_ext.cog_slash(**params["spell"]) @cog_ext.cog_slash(**params["spell"])
async def spell(self, ctx, query): async def spell(self, ctx, query):
spell = self.bot.lookupFuncs.spellFunc(cap(query)) await self.bot.lookupFuncs.spellFunc(ctx, query)
if len(spell) > 2000:
await ctx.send(spell[:2000])
await ctx.send(spell[2000:])
else:
await ctx.send(spell)
# Looks up a monster # Looks up a monster
@cog_ext.cog_slash(**params["monster"]) @cog_ext.cog_slash(**params["monster"])
async def monster(self, ctx, query): async def monster(self, ctx, query):
title, text1, text2, text3, text4, text5 = self.bot.lookupFuncs.monsterFunc(cap(query)) await self.bot.lookupFuncs.monsterFunc(ctx, query)
em1 = discord.Embed(title = title, description = text1, colour=0xDEADBF)
# Sends the received information. Separates into separate messages if
# there is too much text
await ctx.send(embed = em1)
if text2 != "":
if len(text2) < 2048:
em2 = discord.Embed(title = "Special Abilities", description = text2, colour=0xDEADBF)
await ctx.send(embed = em2)
else:
em2 = discord.Embed(title = "Special Abilities", description = text2[:2048], colour=0xDEADBF)
await ctx.send(embed = em2)
em2_2 = discord.Embed(title = "", description = text2[2048:], colour=0xDEADBF)
await ctx.send(embed = em2_2)
if text3 != "":
if len(text3) < 2048:
em3 = discord.Embed(title = "Actions", description = text3, colour=0xDEADBF)
await ctx.send(embed = em3)
else:
em3 = discord.Embed(title = "Actions", description = text3[:2048], colour=0xDEADBF)
await ctx.send(embed = em3)
em3_2 = discord.Embed(title = "", description = text3[2048:], colour=0xDEADBF)
await ctx.send(embed = em3_2)
if text4 != "":
if len(text4) < 2048:
em4 = discord.Embed(title = "Reactions", description = text4, colour=0xDEADBF)
await ctx.send(embed = em4)
else:
em4 = discord.Embed(title = "Reactions", description = text4[:2048], colour=0xDEADBF)
await ctx.send(embed = em4)
em4_2 = discord.Embed(title = "", description = text4[2048:], colour=0xDEADBF)
await ctx.send(embed = em4_2)
if text5 != "":
if len(text5) < 2048:
em5 = discord.Embed(title = "Legendary Actions", description = text5, colour=0xDEADBF)
await ctx.send(embed = em5)
else:
em5 = discord.Embed(title = "Legendary Actions", description = text5[:2048], colour=0xDEADBF)
await ctx.send(embed = em5)
em5_2 = discord.Embed(title = "", description = text5[2048:], colour=0xDEADBF)
await ctx.send(embed = em5_2)
def setup(bot): def setup(bot):
bot.add_cog(LookupCog(bot)) bot.add_cog(LookupCog(bot))

View File

@ -2,16 +2,9 @@ import discord, codecs, string, json
from discord.ext import commands from discord.ext import commands
from discord_slash import cog_ext from discord_slash import cog_ext
from utils import Options from utils import getParams
with open("resources/slashParameters.json", "r") as f: params = getParams()
params = json.load(f)
options = Options()
if options.testing:
for p in params:
params[p]["guild_ids"] = options.guildIds
class MiscCog(commands.Cog): class MiscCog(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
@ -30,31 +23,12 @@ class MiscCog(commands.Cog):
# Restarts the bot # Restarts the bot
@cog_ext.cog_slash(**params["stop"]) @cog_ext.cog_slash(**params["stop"])
async def stop(self, ctx): async def stop(self, ctx):
if "#"+str(ctx.author.id) in self.bot.options.admins: await self.bot.stop(ctx)
await ctx.send("Pulling git repo and restarting...")
self.bot.databaseFuncs.stopServer()
self.bot.log("Logging out.")
await self.bot.logout()
else:
self.bot.log(f"{ctx.author.display_name} tried to stop me! (error code 201)",str(ctx.channel_id))
await ctx.send(f"I don't think I will, {ctx.author.display_name} (error code 201)")
# Gets help for specific command # Gets help for specific command
@cog_ext.cog_slash(**params["help"]) @cog_ext.cog_slash(**params["help"])
async def helpCommand(self, ctx, command = ""): async def helpCommand(self, ctx, command = ""):
if command == "": await self.bot.other.helpFunc(ctx, command)
with codecs.open("resources/help/help.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = "Help", description = text,colour = 0x59f442)
await ctx.send(embed = em)
else:
self.bot.log(f"Looking for help-{command}.txt",str(ctx.channel_id))
with codecs.open(f"resources/help/help-{command}.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = command.capitalize(), description = text,colour = 0x59f442)
await ctx.send(embed = em)
# Lets you thank the bot # Lets you thank the bot
@cog_ext.cog_slash(**params["thank"]) @cog_ext.cog_slash(**params["thank"])
@ -64,67 +38,51 @@ class MiscCog(commands.Cog):
# Sends a friendly message # Sends a friendly message
@cog_ext.cog_slash(**params["hello"]) @cog_ext.cog_slash(**params["hello"])
async def hello(self, ctx): async def hello(self, ctx):
await ctx.send(self.bot.other.helloFunc(ctx.author.display_name)) await self.bot.other.helloFunc(ctx)
# Rolls dice # Rolls dice
@cog_ext.cog_slash(**params["roll"]) @cog_ext.cog_slash(**params["roll"])
async def roll(self, ctx, dice = "1d20"): async def roll(self, ctx, dice = "1d20"):
await ctx.send(self.bot.other.rollDice(ctx.author.display_name, dice)) await self.bot.other.rollDice(ctx, dice)
# Sends a random image # Sends a random image
@cog_ext.cog_slash(**params["image"]) @cog_ext.cog_slash(**params["image"])
async def image(self, ctx): async def image(self, ctx):
await ctx.defer() await self.bot.other.imageFunc(ctx)
await ctx.send(self.bot.other.imageFunc())
# Finds a random movie # Finds a random movie
@cog_ext.cog_slash(**params["movie"]) @cog_ext.cog_slash(**params["movie"])
async def movie(self,ctx): async def movie(self, ctx):
await self.bot.other.movieFunc(ctx) await self.bot.other.movieFunc(ctx)
# Generates a random name # Generates a random name
@cog_ext.cog_slash(**params["name"]) @cog_ext.cog_slash(**params["name"])
async def name(self, ctx): async def name(self, ctx):
await ctx.send(self.generators.nameGen()) await self.generators.nameGen(ctx)
# Generates a random tavern name # Generates a random tavern name
@cog_ext.cog_slash(**params["tavern"]) @cog_ext.cog_slash(**params["tavern"])
async def tavern(self, ctx): async def tavern(self, ctx):
await ctx.send(self.generators.tavernGen()) await self.generators.tavernGen(ctx)
# Finds a page on the Senkulpa wiki # Finds a page on the Senkulpa wiki
@cog_ext.cog_slash(**params["wiki"]) @cog_ext.cog_slash(**params["wiki"])
async def wiki(self, ctx, wikiPage): async def wiki(self, ctx, wikiPage):
await ctx.defer() await self.bot.other.findWikiPage(ctx, wikiPage)
command = string.capwords(wikiPage)
title, content, thumbnail = self.bot.otherfindWikiPage(command)
if title != "":
self.bot.log("Sending the embedded message",str(ctx.channel_id))
content += "\n[Læs mere](https://senkulpa.fandom.com/da/wiki/"+title.replace(" ","_")+")"
embed = discord.Embed(title = title, description = content, colour=0xDEADBF)
if thumbnail != "":
embed.set_thumbnail(url=thumbnail)
await ctx.send(embed = embed)
else:
await ctx.send(content)
#Searches for movie and adds it to Bedre Netflix #Searches for movie and adds it to Bedre Netflix
@cog_ext.cog_slash(**params["addMovie"]) @cog_ext.cog_slash(**params["addMovie"])
async def addMovie(self, ctx, movie): async def addMovie(self, ctx, movie):
await ctx.defer()
await self.bedreNetflix.requestMovie(ctx, movie) await self.bedreNetflix.requestMovie(ctx, movie)
#Searches for show and adds it to Bedre Netflix #Searches for show and adds it to Bedre Netflix
@cog_ext.cog_slash(**params["addShow"]) @cog_ext.cog_slash(**params["addShow"])
async def addShow(self, ctx, show): async def addShow(self, ctx, show):
await ctx.defer()
await self.bedreNetflix.requestShow(ctx, show) await self.bedreNetflix.requestShow(ctx, show)
#Returns currently downloading torrents #Returns currently downloading torrents
@cog_ext.cog_slash(**params["downloading"]) @cog_ext.cog_slash(**params["downloading"])
async def downloading(self, ctx, parameters = "-d"): async def downloading(self, ctx, parameters = "-d"):
await ctx.defer()
await self.bedreNetflix.downloading(ctx, parameters) await self.bedreNetflix.downloading(ctx, parameters)
#Looks up on Wolfram Alpha #Looks up on Wolfram Alpha

View File

@ -1,46 +0,0 @@
from discord.ext import commands
from utils import emojiToCommand
class ReactionCog(commands.Cog):
def __init__(self, bot):
"""Listens for reactions."""
self.bot = bot
@commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
if user.bot == False:
message = reaction.message
channel = message.channel
self.bot.log(f"{user.display_name} reacted to a message",str(channel.id))
try:
connectFourTheirTurn, piece = self.bot.databaseFuncs.connectFourReactionTest(channel,message,"#"+str(user.id))
except:
connectFourTheirTurn = False
bedreNetflixMessage, addMovie, imdbIds = self.bot.databaseFuncs.bedreNetflixReactionTest(channel, message)
if connectFourTheirTurn:
place = emojiToCommand(reaction.emoji)
await self.bot.games.gameLoops.connectFour(message,"place "+str(piece)+" "+str(place),user.id, str(message.channel.id))
elif bedreNetflixMessage and addMovie:
moviePick = emojiToCommand(reaction.emoji)
await message.delete()
if moviePick == "none":
imdbID = None
else:
imdbID = imdbIds[moviePick-1]
await self.bot.other.bedreNetflix.addMovie(channel,imdbID)
elif bedreNetflixMessage and not addMovie:
showPick = emojiToCommand(reaction.emoji)
await message.delete()
if showPick == "none":
imdbName = None
else:
imdbName = imdbIds[showPick-1]
await self.bot.other.bedreNetflix.addShow(channel,imdbName)
elif self.bot.databaseFuncs.hangmanReactionTest(channel,message) and ord(reaction.emoji) in range(127462,127488):
guess = chr(ord(reaction.emoji)-127397)
await self.bot.games.gameLoops.runHangman(channel,"#"+str(user.id),command="guess "+guess)
def setup(bot):
bot.add_cog(ReactionCog(bot))

View File

@ -2,16 +2,9 @@ import discord, string, json
from discord.ext import commands from discord.ext import commands
from discord_slash import cog_ext from discord_slash import cog_ext
from utils import Options, cap from utils import getParams
with open("resources/slashParameters.json", "r") as f: params = getParams()
params = json.load(f)
options = Options()
if options.testing:
for p in params:
params[p]["guild_ids"] = options.guildIds
class starWarsCog(commands.Cog): class starWarsCog(commands.Cog):
@ -22,46 +15,23 @@ class starWarsCog(commands.Cog):
# Rolls star wars dice # Rolls star wars dice
@cog_ext.cog_slash(**params["starWarsRoll"]) @cog_ext.cog_slash(**params["starWarsRoll"])
async def starWarsRoll(self, ctx, dice = ""): async def starWarsRoll(self, ctx, dice = ""):
command = cap(dice) await self.bot.starWars.roll.parseRoll(ctx, dice)
newMessage = self.bot.starWars.roll.parseRoll("#"+str(ctx.author.id),command)
messageList = newMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
await ctx.channel.send(messageItem)
# Controls destiny points # Controls destiny points
@cog_ext.cog_slash(**params["starWarsDestiny"]) @cog_ext.cog_slash(**params["starWarsDestiny"])
async def starWarsDestiny(self, ctx, parameters = ""): async def starWarsDestiny(self, ctx, parameters = ""):
newMessage = self.bot.starWars.destiny.parseDestiny("#"+str(ctx.author.id),parameters) await self.bot.starWars.destiny.parseDestiny(ctx, parameters)
messageList = newMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
await ctx.channel.send(messageItem)
# Rolls for critical injuries # Rolls for critical injuries
@cog_ext.cog_slash(**params["starWarsCrit"]) @cog_ext.cog_slash(**params["starWarsCrit"])
async def starWarsCrit(self, ctx, severity : int = 0): async def starWarsCrit(self, ctx, severity : int = 0):
newMessage = self.bot.starWars.roll.critRoll(int(severity)) await self.bot.starWars.roll.critRoll(ctx, severity)
messageList = newMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
await ctx.channel.send(messageItem)
# Accesses and changes character sheet data with the parseChar function # Accesses and changes character sheet data with the parseChar function
# from funcs/starWarsFuncs/starWarsCharacter.py # from funcs/starWarsFuncs/starWarsCharacter.py
@cog_ext.cog_slash(**params["starWarsCharacter"]) @cog_ext.cog_slash(**params["starWarsCharacter"])
async def starWarsCharacter(self, ctx, parameters = ""): async def starWarsCharacter(self, ctx, parameters = ""):
command = string.capwords(parameters.replace("+","+ ").replace("-","- ").replace(",",", ")) await self.bot.starWars.character.parseChar(ctx, parameters)
title, desc = self.bot.starWars.character.parseChar("#"+str(ctx.author.id),command)
if title != "":
em1 = discord.Embed(title = title, description = desc, colour=0xDEADBF)
await ctx.send(embed = em1)
else:
await ctx.send(desc)
def setup(bot): def setup(bot):
bot.add_cog(starWarsCog(bot)) bot.add_cog(starWarsCog(bot))

View File

@ -3,4 +3,4 @@
__all__ = ["Money", "Games"] __all__ = ["Money", "Games"]
from .money import Money from .money import Money
from .games import Games from .gamesContainer import Games

View File

@ -18,7 +18,7 @@ class Blackjack():
def blackjackShuffle(self, decks, channel): def blackjackShuffle(self, decks, channel):
self.bot.log("Shuffling the blackjack deck") self.bot.log("Shuffling the blackjack deck")
with open("resources/games/deckofCards.txt","r") as f: with open("resources/games/deckOfCards.txt","r") as f:
deck = f.read() deck = f.read()
allDecks = deck.split("\n") * decks allDecks = deck.split("\n") * decks
@ -170,175 +170,223 @@ class Blackjack():
return hand, allStanding, preAllStanding return hand, allStanding, preAllStanding
# When players try to hit # When players try to hit
def blackjackHit(self,channel,user,handNumber = 0): async def hit(self, ctx, handNumber = 0):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
roundDone = False
game = self.bot.database["blackjack games"].find_one({"_id":channel}) game = self.bot.database["blackjack games"].find_one({"_id":channel})
if user in game["user hands"]: if user in game["user hands"]:
hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber) userHands = game["user hands"][user]
hand, handNumber = self.getHandNumber(userHands, handNumber)
if hand != None: if hand == None:
if game["round"] > 0: logMessage = "They didn't specify a hand"
if hand["hit"] == False: sendMessage = "You need to specify a hand"
if hand["standing"] == False: elif game["round"] <= 0:
hand["hand"].append(self.drawCard(channel)) logMessage = "They tried to hit on the 0th round"
hand["hit"] = True sendMessage = "You can't hit before you see your cards"
elif hand["hit"]:
handValue = self.calcHandValue(hand["hand"]) logMessage = "They've already hit this round"
sendMessage = "You've already hit this round"
if handValue > 21: elif hand["standing"]:
hand["busted"] = True logMessage = "They're already standing"
sendMessage = "You can't hit when you're standing"
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}})
response = "accept"
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
return response + str(roundDone)[0] + str(game["round"])
else:
self.bot.log(user+" is already standing")
return "You can't hit when you're standing"
else:
self.bot.log(user+" has already hit this round")
return "You've already hit this round"
else:
self.bot.log(user+" tried to hit on the 0th round")
return "You can't hit before you see your cards"
else: else:
self.bot.log(user+" didn't specify a hand") hand["hand"].append(self.drawCard(channel))
return "You need to specify a hand" hand["hit"] = True
else:
self.bot.log(user+" tried to hit without being in the game")
return "You have to enter the game before you can hit"
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 # When players try to double down
def blackjackDouble(self,channel,user,handNumber = 0): async def double(self, ctx, handNumber = 0):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
roundDone = False
game = self.bot.database["blackjack games"].find_one({"_id":channel}) game = self.bot.database["blackjack games"].find_one({"_id":channel})
if user in game["user hands"]: if user in game["user hands"]:
hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber) hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber)
if hand != None: if hand == None:
if game["round"] > 0: logMessage = "They didn't specify a hand"
if hand["hit"] == False: sendMessage = "You need to specify a hand"
if hand["standing"] == False: elif game["round"] <= 0:
if len(hand["hand"]) == 2: logMessage = "They tried to hit on the 0th round"
bet = hand["bet"] sendMessage = "You can't hit before you see your cards"
if self.bot.money.checkBalance(user) >= bet: elif hand["hit"]:
self.bot.money.addMoney(user,-1 * bet) logMessage = "They've already hit this round"
sendMessage = "You've already hit this round"
hand["hand"].append(self.drawCard(channel)) elif hand["standing"]:
hand["hit"] = True logMessage = "They're already standing"
hand["doubled"] = True sendMessage = "You can't hit when you're standing"
hand["bet"] += bet elif len(hand["hand"]) != 2:
logMessage = "They tried to double after round 1"
handValue = self.calcHandValue(hand["hand"]) sendMessage = "You can only double on the first round"
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}))
return "Adding another "+str(bet)+" GwendoBucks to "+self.bot.databaseFuncs.getName(user)+"'s bet and drawing another card.",str(roundDone)[0] + str(game["round"])
else:
self.bot.log(user+" doesn't have enough GwendoBucks")
return "You don't have enough GwendoBucks",""
else:
self.bot.log(user+" tried to double on round "+str(game["round"]))
return "You can only double down on the first round",""
else:
self.bot.log(user+" is already standing")
return "You can't double when you're standing",""
else:
self.bot.log(user+" has already hit this round")
return "You've already hit this round",""
else:
self.bot.log(user+" tried to double on the 0th round")
return "You can't double down before you see your cards",""
else: else:
self.bot.log(user+" didn't specify a hand") bet = hand["bet"]
return "You need to specify which hand" 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: else:
self.bot.log(user+" tried to double without being in the game") logMessage = "They tried to double without being in the game"
return "You can't double when you're not 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 # When players try to stand
def blackjackStand(self,channel,user,handNumber = 0): async def stand(self, ctx, handNumber = 0):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
roundDone = False
game = self.bot.database["blackjack games"].find_one({"_id":channel}) game = self.bot.database["blackjack games"].find_one({"_id":channel})
if user in game["user hands"]: if user in game["user hands"]:
hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber) hand, handNumber = self.getHandNumber(game["user hands"][user],handNumber)
if hand != None: if hand == None:
if game["round"] > 0: sendMessage = "You need to specify which hand"
if hand["hit"] == False: logMessage = "They didn't specify a hand"
if hand["standing"] == False: elif game["round"] <= 0:
hand["standing"] = True sendMessage = "You can't stand before you see your cards"
logMessage = "They tried to stand on round 0"
if handNumber == 2: elif hand["hit"]:
self.bot.database["blackjack games"].update_one({"_id":channel}, sendMessage = "You've already hit this round"
{"$set":{"user hands."+user+".other hand":hand}}) logMessage = "They'd already hit this round"
elif handNumber == 3: elif hand["standing"]:
self.bot.database["blackjack games"].update_one({"_id":channel}, sendMessage = "You're already standing"
{"$set":{"user hands."+user+".third hand":hand}}) logMessage = "They're already standing"
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}})
response = "accept"
roundDone = self.isRoundDone(self.bot.database["blackjack games"].find_one({"_id":channel}))
return response + str(roundDone)[0] + str(game["round"])
else:
self.bot.log(user+" is already standing")
return "You're already standing"
else:
self.bot.log(user+" has already hit this round")
return "You've already hit this round"
else:
self.bot.log(user+" tried to stand on the first round")
return "You can't stand before you see your cards"
else: else:
self.bot.log(user+" didn't specify a hand") hand["standing"] = True
return "You need to specify which hand"
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: else:
self.bot.log(user+" tried to stand without being in the game") logMessage = "They tried to stand without being in the game"
return "You have to enter the game before you can stand" 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 # When players try to split
def blackjackSplit(self,channel,user,handNumber = 0): async def split(self, ctx, handNumber = 0):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
roundDone = False
handNumberError = False
game = self.bot.database["blackjack games"].find_one({"_id":channel}) game = self.bot.database["blackjack games"].find_one({"_id":channel})
if game["user hands"][user]["split"] == 0: if game["user hands"][user]["split"] == 0:
@ -347,166 +395,200 @@ class Blackjack():
handNumber = 0 handNumber = 0
otherHand = 2 otherHand = 2
else: else:
if handNumber != 0: if handNumber == 1:
if handNumber == 1: hand = game["user hands"][user]
hand = game["user hands"][user] elif handNumber == 2:
elif handNumber == 2: hand = game["user hands"][user]["other hand"]
hand = game["user hands"][user]["other hand"] elif handNumber == 3:
elif handNumber == 3: hand = game["user hands"][user]["third hand"]
hand = game["user hands"][user]["third hand"]
else:
self.bot.log(user+" tried to hit without specifying which hand")
return "You have to specify the hand you're hitting with."
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
else: else:
self.bot.log(user+" tried to split without specifying which hand") handNumberError = True
return "You have to specify the hand you're splitting.",""
if game["user hands"][user]["split"] < 3: if game["user hands"][user]["split"] == 1:
if game["round"] != 0: newHand = game["user hands"][user]["third hand"]
if hand["hit"] == False: otherHand = 3
if hand["standing"] == False:
if len(hand["hand"]) == 2:
firstCard = self.calcHandValue([hand["hand"][0]])
secondCard = self.calcHandValue([hand["hand"][1]])
if firstCard == secondCard:
bet = hand["bet"]
if self.bot.money.checkBalance(user) >= bet:
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}))
return "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.",str(roundDone)[0] + str(game["round"])
else:
self.bot.log(user+" doesn't have enough GwendoBucks")
return "You don't have enough GwendoBucks",""
else:
self.bot.log(user+" tried to split 2 different cards")
return "Your cards need to have the same value to split",""
else:
self.bot.log(user+" tried to split later than they could")
return "You can only split on the first round",""
else:
self.bot.log(user+" is already standing")
return "You can't split when you're standing",""
else:
self.bot.log(user+" has already hit this round")
return "You've already hit this round",""
else: else:
self.bot.log(user+" tried to split on the 0th round") newHand = game["user hands"][user]["fourth hand"]
return "You can't split before you see your cards","" 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: else:
self.bot.log(user+" tried to split more than three times") firstCard = self.calcHandValue([hand["hand"][0]])
return "You can only split 3 times","" 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 # Player enters the game and draws a hand
def blackjackPlayerDrawHand(self,channel,user,bet): async def playerDrawHand(self, ctx, bet : int):
game = self.bot.database["blackjack games"].find_one({"_id":channel}) try:
await ctx.defer()
except:
self.bot.log("Defer failed")
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(self.bot.databaseFuncs.getName(user)+" is trying to join the game in "+channel) self.bot.log(f"{userName} is trying to join the Blackjack game")
if game != None: if game == None:
if user not in game["user hands"]: sendMessage = "There is no game going on in this channel"
if len(game["user hands"]) < 5: logMessage = sendMessage
if game["round"] == 0: elif user in game["user hands"]:
if bet >= 0: sendMessage = "You're already in the game!"
if self.bot.money.checkBalance(user) >= bet: logMessage = "They're already in the game"
self.bot.money.addMoney(user,-1 * bet) elif len(game["user hands"]) >= 5:
playerHand = [self.drawCard(channel),self.drawCard(channel)] sendMessage = "There can't be more than 5 players in a game"
logMessage = "There were already 5 players in the game"
handValue = self.calcHandValue(playerHand) elif game["round"] != 0:
sendMessage = "The table is no longer taking bets"
if handValue == 21: logMessage = "They tried to join after the game begun"
blackjackHand = True elif bet < 0:
else: sendMessage = "You can't bet a negative amount"
blackjackHand = False logMessage = "They tried to bet a negative amount"
elif self.bot.money.checkBalance(user) < bet:
newHand = {"hand":playerHand, sendMessage = "You don't have enough GwendoBucks"
"bet":bet,"standing":False,"busted":False,"blackjack":blackjackHand,"hit":True, logMessage = "They didn't have enough GwendoBucks"
"doubled":False,"split":0,"other hand":{},"third hand":{},"fourth hand":{}}
self.bot.database["blackjack games"].update_one({"_id":channel},
{"$set":{"user hands."+user:newHand}})
self.bot.log(f"{self.bot.databaseFuncs.getName(user)} entered the game with a bet of {bet}")
return f"{self.bot.databaseFuncs.getName(user)} entered the game with a bet of {bet}"
else:
self.bot.log(user+" doesn't have enough GwendoBucks")
return "You don't have enough GwendoBucks to place that bet"
else:
self.bot.log(user+" tried to bet a negative amount")
return "You can't bet a negative amount"
else:
self.bot.log("The table is no longer open for bets")
return "The table is no longer open for bets"
else:
self.bot.log("There are already 5 players in the game.")
return "There's already a maximum of players at the table."
else:
self.bot.log(user+" is already in the game")
return "You've already entered this game"
else: else:
self.bot.log("There is no game going on in "+channel) self.bot.money.addMoney(user,-1 * bet)
return "There is no game going on in this channel" 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 # Starts a game of blackjack
def blackjackStart(self,channel:str): async def start(self, ctx):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
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}) game = self.bot.database["blackjack games"].find_one({"_id":channel})
self.bot.log("Trying to start a blackjack game in "+channel) self.bot.log("Trying to start a blackjack game in "+channel)
gameStarted = False
if game == None: if game == None:
@ -522,10 +604,39 @@ class Blackjack():
copyfile("resources/games/blackjackTable.png","resources/games/blackjackTables/blackjackTable"+channel+".png") copyfile("resources/games/blackjackTable.png","resources/games/blackjackTables/blackjackTable"+channel+".png")
return "started" 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: else:
self.bot.log("There is already a blackjack game going on in "+channel) await ctx.channel.send("There's already a blackjack game going on. Try again in a few minutes.")
return "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 # Ends the game and calculates winnings
def blackjackFinish(self,channel): def blackjackFinish(self,channel):
@ -562,7 +673,6 @@ class Blackjack():
return finalWinnings return finalWinnings
def calcWinnings(self,hand, dealerValue, topLevel, dealerBlackjack, dealerBusted): def calcWinnings(self,hand, dealerValue, topLevel, dealerBlackjack, dealerBusted):
self.bot.log("Calculating winnings") self.bot.log("Calculating winnings")
reason = "" reason = ""
@ -703,178 +813,34 @@ class Blackjack():
else: else:
self.bot.log("Ending loop on round "+str(gameRound),str(channel.id)) self.bot.log("Ending loop on round "+str(gameRound),str(channel.id))
async def parseBlackjack(self,content, ctx): # Returning current hi-lo value
# Blackjack shuffle variables async def hilo(self, ctx):
blackjackMinCards = 50
blackjackDecks = 4
channel = ctx.channel_id channel = ctx.channel_id
# Starts the game data = self.bot.database["hilo"].find_one({"_id":str(channel)})
if content == "": if data != None:
await ctx.send("Starting a new game of blackjack") hilo = str(data["hilo"])
cardsLeft = 0
cards = self.bot.database["blackjack cards"].find_one({"_id":str(channel)})
if cards != None:
cardsLeft = len(cards["cards"])
# Shuffles if not enough cards
if cardsLeft < blackjackMinCards:
self.blackjackShuffle(blackjackDecks,str(channel))
self.bot.log("Shuffling the blackjack deck...",str(channel))
await ctx.channel.send("Shuffling the deck...")
new_message = self.blackjackStart(str(channel))
if new_message == "started":
new_message = "Blackjack game started. Use \"/blackjack bet [amount]\" to enter the game within the next 30 seconds."
await ctx.channel.send(new_message)
oldImage = await ctx.channel.send(file = discord.File("resources/games/blackjackTables/blackjackTable"+str(channel)+".png"))
with open("resources/games/oldImages/blackjack"+str(channel), "w") as f:
f.write(str(oldImage.id))
await asyncio.sleep(30)
gamedone = False
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("/blackjack calling self.blackjackLoop()",str(channel))
await self.blackjackLoop(ctx.channel,1,gameID)
else:
new_message = self.blackjackFinish(str(channel))
await ctx.channel.send(new_message)
else:
await ctx.channel.send(new_message)
# Entering game and placing bet
elif content.startswith("bet"):
commands = content.split(" ")
amount = int(commands[1])
response = self.blackjackPlayerDrawHand(str(channel),"#"+str(ctx.author.id),amount)
await ctx.send(response)
# Hitting
elif content.startswith("hit"):
if content == "hit":
response = self.blackjackHit(str(channel),"#"+str(ctx.author.id))
else:
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response = self.blackjackHit(str(channel),"#"+str(ctx.author.id),handNumber)
if response.startswith("accept"):
await ctx.send(f"{ctx.author.display_name} hit")
#try:
if response[6] == "T":
gameID = self.bot.database["blackjack games"].find_one({"_id":str(channel)})["gameID"]
self.bot.log("Hit calling self.blackjackLoop()",str(channel))
await self.blackjackLoop(ctx.channel,int(response[7:])+1,gameID)
#except:
# self.bot.log("Something fucked up (error code 1320)",str(channel))
else:
await ctx.send(response)
# Standing
elif content.startswith("stand"):
if content == "hit":
response = self.blackjackStand(str(channel),"#"+str(ctx.author.id))
else:
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response = self.blackjackStand(str(channel),"#"+str(ctx.author.id),handNumber)
if response.startswith("accept"):
await ctx.send(f"{ctx.author.display_name} is standing")
#try:
if response[6] == "T":
gameID = self.bot.database["blackjack games"].find_one({"_id":str(channel)})["gameID"]
self.bot.log("Stand calling self.blackjackLoop()",str(channel))
await self.blackjackLoop(ctx.channel,int(response[7:])+1,gameID)
#except:
# self.bot.log("Something fucked up (error code 1320)",str(channel))
else:
await ctx.send(response)
# Doubling bet
elif content.startswith("double"):
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response, roundDone = self.blackjackDouble(str(channel),"#"+str(ctx.author.id),handNumber)
await ctx.send(response)
try:
if roundDone[0] == "T":
gameID = self.bot.database["blackjack games"].find_one({"_id":str(channel)})["gameID"]
self.bot.log("Double calling self.blackjackLoop()",str(channel))
await self.blackjackLoop(ctx.channel,int(roundDone[1:])+1,gameID)
except:
self.bot.log("Something fucked up (error code 1320)",str(channel))
# Splitting hand
elif content.startswith("split"):
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response, roundDone = self.blackjackSplit(str(channel),"#"+str(ctx.author.id),handNumber)
await ctx.send(response)
try:
if roundDone[0] == "T":
gameID = self.bot.database["blackjack games"].find_one({"_id":str(channel)})["gameID"]
self.bot.log("Split calling self.blackjackLoop()",str(channel))
await self.blackjackLoop(ctx.channel,int(roundDone[1:])+1,gameID)
except:
self.bot.log("Something fucked up (error code 1320)")
# Returning current hi-lo value
elif content.startswith("hilo"):
data = self.bot.database["hilo"].find_one({"_id":str(channel)})
if data != None:
hilo = str(data["hilo"])
else:
hilo = "0"
await ctx.send(hilo, hidden=True)
# Shuffles the blackjack deck
elif content.startswith("shuffle"):
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
elif content.startswith("cards"):
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(str(cardsLeft)+" cards, "+str(decksLeft)+" decks", hidden=True)
else: else:
self.bot.log("Not a command (error code 1301)") hilo = "0"
await ctx.send("I didn't quite understand that (error code 1301)") 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)

View File

@ -1,10 +1,11 @@
import random import random
import copy import copy
import math import math
import discord
from .connectFourDraw import drawConnectFour from .connectFourDraw import drawConnectFour
AIScores = { AISCORES = {
"middle": 3, "middle": 3,
"two in a row": 10, "two in a row": 10,
"three in a row": 50, "three in a row": 50,
@ -15,75 +16,127 @@ AIScores = {
"avoid losing": 100 "avoid losing": 100
} }
rowCount = 6 ROWCOUNT = 6
columnCount = 7 COLUMNCOUNT = 7
easy = True
class connectFour(): class ConnectFour():
def __init__(self,bot): def __init__(self,bot):
self.bot = bot self.bot = bot
self.draw = drawConnectFour(bot) self.draw = drawConnectFour(bot)
# Starts the game # Starts the game
def connectFourStart(self, channel, user, opponent): async def start(self, ctx, opponent):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
user = f"#{ctx.author.id}"
channel = str(ctx.channel_id)
game = self.bot.database["connect 4 games"].find_one({"_id":channel}) game = self.bot.database["connect 4 games"].find_one({"_id":channel})
if game == None: startedGame = False
canStart = True
if opponent in ["1","2","3","4","5"]: if game != None:
difficulty = int(opponent) sendMessage = "There's already a connect 4 game going on in this channel"
diffText = " with difficulty "+opponent logMessage = "There was already a game going on"
opponent = "Gwendolyn" canStart = False
elif opponent.lower() == "gwendolyn": else:
difficulty = 3 if type(opponent) == int:
diffText = " with difficulty 3" # Opponent is Gwendolyn
opponent = "Gwendolyn" if opponent in range(1, 6):
else: difficulty = int(opponent)
try: diffText = f" with difficulty {difficulty}"
int(opponent) opponent = f"#{self.bot.user.id}"
return "That difficulty doesn't exist", False, False, False, False else:
except: sendMessage = "Difficulty doesn't exist"
logMessage = "They tried to play against a difficulty that doesn't exist"
canStart = False
elif type(opponent) == discord.member.Member:
if opponent.bot:
# User has challenged a bot
if opponent == self.bot.user:
# It was Gwendolyn
difficulty = 3
diffText = f" with difficulty {difficulty}"
opponent = f"#{self.bot.user.id}"
else:
sendMessage = "You can't challenge a bot!"
logMessage = "They tried to challenge a bot"
canStart = False
else:
# Opponent is another player # Opponent is another player
opponent = self.bot.databaseFuncs.getID(opponent) if ctx.author != opponent:
if opponent != None: opponent = f"#{opponent.id}"
difficulty = 5 difficulty = 5
diffText = "" diffText = ""
else: else:
return "I can't find that user", False, False, False, False sendMessage = "You can't play against yourself"
logMessage = "They tried to play against themself"
canStart = False
if user == opponent: if canStart:
return "You can't play against yourself", False, False, False, False board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)]
players = [user, opponent]
board = [ [ 0 for i in range(columnCount) ] for j in range(rowCount) ]
players = [user,opponent]
random.shuffle(players) random.shuffle(players)
newGame = {"_id":channel,"board": board,"winner":0,"win direction":"", newGame = {"_id":channel, "board": board, "winner":0,
"win coordinates":[0,0],"players":players,"turn":0,"difficulty":difficulty} "win direction":"", "win coordinates":[0, 0],
"players":players, "turn":0, "difficulty":difficulty}
self.bot.database["connect 4 games"].insert_one(newGame) self.bot.database["connect 4 games"].insert_one(newGame)
self.draw.drawImage(channel) self.draw.drawImage(channel)
gwendoTurn = False gwendoTurn = (players[0] == f"#{self.bot.user.id}")
startedGame = True
if players[0] == "Gwendolyn": opponentName = self.bot.databaseFuncs.getName(opponent)
gwendoTurn = True turnName = self.bot.databaseFuncs.getName(players[0])
return "Started game against "+self.bot.databaseFuncs.getName(opponent)+diffText+". It's "+self.bot.databaseFuncs.getName(players[0])+"'s turn", True, False, False, gwendoTurn startedText = f"Started game against {opponentName}{diffText}."
else: turnText = f"It's {turnName}'s turn"
return "There's already a connect 4 game going on in this channel", False, False, False, False sendMessage = f"{startedText} {turnText}"
logMessage = "They started a game"
self.bot.log(logMessage)
await ctx.send(sendMessage)
# Sets the whole game in motion
if startedGame:
filePath = f"resources/games/connect4Boards/board{ctx.channel_id}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
with open(f"resources/games/oldImages/connectFour{ctx.channel_id}", "w") as f:
f.write(str(oldImage.id))
if gwendoTurn:
await self.connectFourAI(ctx)
else:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
# Places a piece at the lowest available point in a specific column # Places a piece at the lowest available point in a specific column
def placePiece(self, channel : str,player : int,column : int): async def placePiece(self, ctx, user, column):
channel = str(ctx.channel.id)
game = self.bot.database["connect 4 games"].find_one({"_id":channel}) game = self.bot.database["connect 4 games"].find_one({"_id":channel})
playerNumber = game["players"].index(user)+1
userName = self.bot.databaseFuncs.getName(user)
placedPiece = False
if game != None: if game is None:
sendMessage = "There's no game in this channel"
logMessage = "There was no game in the channel"
else:
board = game["board"] board = game["board"]
board = self.placeOnBoard(board, playerNumber, column)
board = self.placeOnBoard(board,player,column) if board is None:
sendMessage = "There isn't any room in that column"
if board != None: logMessage = "There wasn't any room in the column"
else:
self.bot.database["connect 4 games"].update_one({"_id":channel},{"$set":{"board":board}}) self.bot.database["connect 4 games"].update_one({"_id":channel},{"$set":{"board":board}})
turn = (game["turn"]+1)%2 turn = (game["turn"]+1)%2
self.bot.database["connect 4 games"].update_one({"_id":channel},{"$set":{"turn":turn}}) self.bot.database["connect 4 games"].update_one({"_id":channel},{"$set":{"turn":turn}})
@ -98,82 +151,115 @@ class connectFour():
self.bot.database["connect 4 games"].update_one({"_id":channel}, self.bot.database["connect 4 games"].update_one({"_id":channel},
{"$set":{"win coordinates":winCoordinates}}) {"$set":{"win coordinates":winCoordinates}})
message = self.bot.databaseFuncs.getName(game["players"][won-1])+" placed a piece in column "+str(column+1)+" and won." sendMessage = f"{userName} placed a piece in column {column+1} and won."
logMessage = f"{userName} won"
winAmount = int(game["difficulty"])**2+5 winAmount = int(game["difficulty"])**2+5
if game["players"][won-1] != "Gwendolyn": if game["players"][won-1] != f"#{self.bot.user.id}":
message += " Adding "+str(winAmount)+" GwendoBucks to their account." sendMessage += " Adding "+str(winAmount)+" GwendoBucks to their account"
elif 0 not in board[0]: elif 0 not in board[0]:
gameWon = True gameWon = True
message = "It's a draw!" sendMessage = "It's a draw!"
logMessage = "The game ended in a draw"
else: else:
gameWon = False gameWon = False
message = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed a piece in column "+str(column+1)+". It's now "+self.bot.databaseFuncs.getName(game["players"][turn])+"'s turn." otherUserName = self.bot.databaseFuncs.getName(game["players"][turn])
sendMessage = f"{userName} placed a piece in column {column+1}. It's now {otherUserName}'s turn"
logMessage = "They placed the piece"
gwendoTurn = False gwendoTurn = (game["players"][turn] == f"#{self.bot.user.id}")
if game["players"][turn] == "Gwendolyn": placedPiece = True
self.bot.log("It's Gwendolyn's turn")
gwendoTurn = True
self.draw.drawImage(channel) await ctx.channel.send(sendMessage)
return message, True, True, gameWon, gwendoTurn self.bot.log(logMessage)
if placedPiece:
self.draw.drawImage(channel)
with open(f"resources/games/oldImages/connectFour{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else: else:
return "There isn't any room in that column", True, True, False, False self.bot.log("The old image was already deleted")
else:
return "There's no game in this channel", False, False, False, False filePath = f"resources/games/connect4Boards/board{channel}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
if gameWon:
self.endGame(channel)
else:
with open(f"resources/games/oldImages/connectFour{channel}", "w") as f:
f.write(str(oldImage.id))
if gwendoTurn:
await self.connectFourAI(ctx)
else:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
# Returns a board where a piece has been placed in the column # Returns a board where a piece has been placed in the column
def placeOnBoard(self,board,player,column): def placeOnBoard(self, board, player, column):
placementx, placementy = -1, column placementX, placementY = -1, column
for x, line in enumerate(board): for x, line in enumerate(board):
if line[column] == 0: if line[column] == 0:
placementx = x placementX = x
board[placementx][placementy] = player board[placementX][placementY] = player
if placementx == -1: if placementX == -1:
return None return None
else: else:
return board return board
def endGame(self, channel):
game = self.bot.database["connect 4 games"].find_one({"_id":channel})
winner = game["winner"]
if winner != 0:
if game["players"][winner-1] != f"#{self.bot.user.id}":
difficulty = int(game["difficulty"])
reward = difficulty**2 + 5
self.bot.money.addMoney(game["players"][winner-1], reward)
self.bot.databaseFuncs.deleteGame("connect 4 games", channel)
# Parses command # Parses command
def parseconnectFour(self, command, channel, user): async def surrender(self, ctx):
commands = command.split() try:
if command == "" or command == " ": await ctx.defer()
return "I didn't get that. Use \"/connectFour start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False except:
elif commands[0] == "start": self.bot.log("Defer failed")
# Starting a game channel = str(ctx.channel_id)
if len(commands) == 1: # if the commands is "/connectFour start", the opponent is Gwendolyn game = self.bot.database["connect 4 games"].find_one({"_id":channel})
commands.append("3")
return self.connectFourStart(channel,user,commands[1]) # commands[1] is the opponent
# Stopping the game if f"#{ctx.author.id}" in game["players"]:
elif commands[0] == "stop": loserIndex = game["players"].index(f"#{ctx.author.id}")
game = self.bot.database["connect 4 games"].find_one({"_id":channel}) winnerIndex = (loserIndex+1)%2
winnerID = game["players"][winnerIndex]
winnerName = self.bot.databaseFuncs.getName(winnerID)
if user in game["players"]: sendMessage = f"{ctx.author.display_name} surrenders."
return "Ending game.", False, False, True, False sendMessage += f" This means {winnerName} is the winner."
if winnerID != f"#{self.bot.user.id}":
difficulty = int(game["difficulty"])
reward = difficulty**2 + 5
sendMessage += f" Adding {reward} to their account"
await ctx.send(sendMessage)
with open(f"resources/games/oldImages/connectFour{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else: else:
return "You can't end a game where you're not a player.", False, False, False, False self.bot.log("The old image was already deleted")
# Placing manually self.endGame(channel)
elif commands[0] == "place":
if len(commands) == 2:
game = self.bot.database["connect 4 games"].find_one({"_id":channel})
turn = game["turn"]
if user == game["players"][turn]:
piece = turn + 1
else:
self.bot.log("It wasn't their turn")
return "It's not your turn!", False, False, False, False
column = int(commands[1])-1
else:
column = int(commands[2])-1
piece = int(commands[1])
return self.placePiece(channel, piece, column)
else: else:
return "I didn't get that. Use \"/connectFour start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False await ctx.send("You can't surrender when you're not a player")
# Checks if someone has won the game and returns the winner # Checks if someone has won the game and returns the winner
def isWon(self, board): def isWon(self, board):
@ -181,13 +267,13 @@ class connectFour():
winDirection = "" winDirection = ""
winCoordinates = [0,0] winCoordinates = [0,0]
for row in range(rowCount): for row in range(ROWCOUNT):
for place in range(columnCount): for place in range(COLUMNCOUNT):
if won == 0: if won == 0:
piecePlayer = board[row][place] piecePlayer = board[row][place]
if piecePlayer != 0: if piecePlayer != 0:
# Checks horizontal # Checks horizontal
if place <= columnCount-4: if place <= COLUMNCOUNT-4:
pieces = [board[row][place+1],board[row][place+2],board[row][place+3]] pieces = [board[row][place+1],board[row][place+2],board[row][place+3]]
else: else:
pieces = [0] pieces = [0]
@ -198,7 +284,7 @@ class connectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks vertical # Checks vertical
if row <= rowCount-4: if row <= ROWCOUNT-4:
pieces = [board[row+1][place],board[row+2][place],board[row+3][place]] pieces = [board[row+1][place],board[row+2][place],board[row+3][place]]
else: else:
pieces = [0] pieces = [0]
@ -209,7 +295,7 @@ class connectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks right diagonal # Checks right diagonal
if row <= rowCount-4 and place <= columnCount-4: if row <= ROWCOUNT-4 and place <= COLUMNCOUNT-4:
pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]] pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
else: else:
pieces = [0] pieces = [0]
@ -220,7 +306,7 @@ class connectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks left diagonal # Checks left diagonal
if row <= rowCount-4 and place >= 3: if row <= ROWCOUNT-4 and place >= 3:
pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]] pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
else: else:
pieces = [0] pieces = [0]
@ -234,21 +320,23 @@ class connectFour():
return won, winDirection, winCoordinates return won, winDirection, winCoordinates
# Plays as the AI # Plays as the AI
async def connectFourAI(self, channel): async def connectFourAI(self, ctx):
channel = str(ctx.channel.id)
self.bot.log("Figuring out best move") self.bot.log("Figuring out best move")
game = self.bot.database["connect 4 games"].find_one({"_id":channel}) game = self.bot.database["connect 4 games"].find_one({"_id":channel})
board = game["board"] board = game["board"]
player = game["players"].index("Gwendolyn")+1 player = game["players"].index(f"#{self.bot.user.id}")+1
difficulty = game["difficulty"] difficulty = game["difficulty"]
scores = [-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf] scores = [-math.inf for _ in range(COLUMNCOUNT)]
for column in range(0,columnCount): for column in range(COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
scores[column] = await self.minimax(testBoard,difficulty,player%2+1,player,-math.inf,math.inf,False) scores[column] = await self.minimax(testBoard,difficulty,player%2+1,player,-math.inf,math.inf,False)
self.bot.log("Best score for column "+str(column)+" is "+str(scores[column])) self.bot.log(f"Best score for column {column} is {scores[column]}")
possibleScores = scores.copy() possibleScores = scores.copy()
@ -257,9 +345,10 @@ class connectFour():
highest_score = random.choice(possibleScores) highest_score = random.choice(possibleScores)
indices = [i for i, x in enumerate(scores) if x == highest_score] bestColumns = [i for i, x in enumerate(scores) if x == highest_score]
placement = random.choice(indices) placement = random.choice(bestColumns)
return self.placePiece(channel,player,placement)
await self.placePiece(ctx, f"#{self.bot.user.id}", placement)
# Calculates points for a board # Calculates points for a board
def AICalcPoints(self,board,player): def AICalcPoints(self,board,player):
@ -268,28 +357,28 @@ class connectFour():
# Adds points for middle placement # Adds points for middle placement
# Checks horizontal # Checks horizontal
for row in range(rowCount): for row in range(ROWCOUNT):
if board[row][3] == player: if board[row][3] == player:
score += AIScores["middle"] score += AISCORES["middle"]
rowArray = [int(i) for i in list(board[row])] rowArray = [int(i) for i in list(board[row])]
for place in range(columnCount-3): for place in range(COLUMNCOUNT-3):
window = rowArray[place:place+4] window = rowArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
# Checks Vertical # Checks Vertical
for column in range(columnCount): for column in range(COLUMNCOUNT):
columnArray = [int(i[column]) for i in list(board)] columnArray = [int(i[column]) for i in list(board)]
for place in range(rowCount-3): for place in range(ROWCOUNT-3):
window = columnArray[place:place+4] window = columnArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
# Checks right diagonal # Checks right diagonal
for row in range(rowCount-3): for row in range(ROWCOUNT-3):
for place in range(columnCount-3): for place in range(COLUMNCOUNT-3):
window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]] window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
for place in range(3,columnCount): for place in range(3,COLUMNCOUNT):
window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]] window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
@ -299,20 +388,19 @@ class connectFour():
## Add points if AI wins ## Add points if AI wins
#if won == player: #if won == player:
# score += AIScores["win"] # score += AISCORES["win"]
return score return score
def evaluateWindow(self, window,player,otherPlayer): def evaluateWindow(self, window,player,otherPlayer):
if window.count(player) == 4: if window.count(player) == 4:
return AIScores["win"] return AISCORES["win"]
elif window.count(player) == 3 and window.count(0) == 1: elif window.count(player) == 3 and window.count(0) == 1:
return AIScores["three in a row"] return AISCORES["three in a row"]
elif window.count(player) == 2 and window.count(0) == 2: elif window.count(player) == 2 and window.count(0) == 2:
return AIScores["two in a row"] return AISCORES["two in a row"]
elif window.count(otherPlayer) == 4: elif window.count(otherPlayer) == 4:
return AIScores["enemy win"] return AISCORES["enemy win"]
else: else:
return 0 return 0
@ -325,24 +413,24 @@ class connectFour():
return points return points
if maximizingPlayer: if maximizingPlayer:
value = -math.inf value = -math.inf
for column in range(0,columnCount): for column in range(0,COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False) evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False)
if evaluation < -9000: evaluation += AIScores["avoid losing"] if evaluation < -9000: evaluation += AISCORES["avoid losing"]
value = max(value,evaluation) value = max(value,evaluation)
alpha = max(alpha,evaluation) alpha = max(alpha,evaluation)
if beta <= alpha: break if beta <= alpha: break
return value return value
else: else:
value = math.inf value = math.inf
for column in range(0,columnCount): for column in range(0,COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True) evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True)
if evaluation < -9000: evaluation += AIScores["avoid losing"] if evaluation < -9000: evaluation += AISCORES["avoid losing"]
value = min(value,evaluation) value = min(value,evaluation)
beta = min(beta,evaluation) beta = min(beta,evaluation)
if beta <= alpha: break if beta <= alpha: break

View File

@ -1,172 +0,0 @@
import asyncio
import discord
class GameLoops():
def __init__(self,bot):
self.bot = bot
# Deletes a message
async def deleteMessage(self, imageLocation,channel):
try:
with open("resources/games/oldImages/"+imageLocation, "r") as f:
messages = f.read().splitlines()
for message in messages:
oldMessage = await channel.fetch_message(int(message))
self.bot.log("Deleting old message")
await oldMessage.delete()
except:
oldMessage = ""
return oldMessage
# Runs connect four
async def connectFour(self, ctx, command, user = None, channelId = None):
if user is None:
user = "#"+str(ctx.author.id)
if channelId is None:
channelId = str(ctx.channel_id)
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.games.connectFour.parseconnectFour(command,channelId, user)
if hasattr(ctx, "send"):
await ctx.send(response)
else:
await ctx.channel.send(response)
self.bot.log(response, channelId)
if showImage:
if deleteImage:
oldImage = await self.deleteMessage("connectFour"+channelId,ctx.channel)
oldImage = await ctx.channel.send(file = discord.File("resources/games/connect4Boards/board"+channelId+".png"))
if gameDone == False:
if gwendoTurn:
response, showImage, deleteImage, gameDone, gwendoTurn = await self.bot.games.connectFour.connectFourAI(channelId)
await ctx.channel.send(response)
self.bot.log(response,channelId)
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await ctx.channel.send(file = discord.File("resources/games/connect4Boards/board"+channelId+".png"))
if gameDone == False:
with open("resources/games/oldImages/connectFour"+channelId, "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
except:
self.bot.log("Image deleted before I could react to all of them")
else:
with open("resources/games/oldImages/connectFour"+channelId, "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
except:
self.bot.log("Image deleted before I could react to all of them")
if gameDone:
game = self.bot.database["connect 4 games"].find_one({"_id":channelId})
try:
with open("resources/games/oldImages/connectFour"+channelId, "r") as f:
oldImage = await channel.fetch_message(int(f.read()))
await oldImage.delete()
except:
self.bot.log("The old image was already deleted")
winner = game["winner"]
difficulty = int(game["difficulty"])
reward = difficulty**2 + 5
if winner != 0:
if game["players"][winner-1].lower() != "gwendolyn":
self.bot.money.addMoney(game["players"][winner-1].lower(),reward)
self.bot.databaseFuncs.deleteGame("connect 4 games",channelId)
async def runHangman(self,channel,user,command = "start", ctx = None):
try:
response, showImage, deleteImage, remainingLetters = self.bot.games.hangman.parseHangman(str(channel.id),user,command)
except:
self.bot.log("Error parsing command (error code 1701)")
if response != "":
if ctx is None:
await channel.send(response)
else:
await ctx.send(response)
self.bot.log(response,str(channel.id))
if showImage:
if deleteImage:
await self.deleteMessage("hangman"+str(channel.id),channel)
oldImage = await channel.send(file = discord.File("resources/games/hangmanBoards/hangmanBoard"+str(channel.id)+".png"))
if len(remainingLetters) > 15:
otherMessage = await channel.send("_ _")
reactionMessages = {oldImage : remainingLetters[:15],otherMessage : remainingLetters[15:]}
else:
otherMessage = ""
reactionMessages = {oldImage : remainingLetters}
oldMessages = str(oldImage.id)
if otherMessage != "":
oldMessages += "\n"+str(otherMessage.id)
with open("resources/games/oldImages/hangman"+str(channel.id), "w") as f:
f.write(oldMessages)
try:
for message, letters in reactionMessages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
except:
self.bot.log("Image deleted before adding all reactions")
# Runs Hex
async def runHex(self,ctx,command,user):
channelId = ctx.channel_id
try:
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.games.hex.parseHex(command,str(channelId),user)
except:
self.bot.log("Error parsing command (error code 1510)")
await ctx.send(response)
self.bot.log(response,str(channelId))
if showImage:
if deleteImage:
try:
oldImage = await self.deleteMessage("hex"+str(channelId),ctx.channel)
except:
self.bot.log("Error deleting old image (error code 1501)")
oldImage = await ctx.channel.send(file = discord.File("resources/games/hexBoards/board"+str(channelId)+".png"))
if gwendoTurn and not gameDone:
try:
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.games.hex.hexAI(str(channelId))
except:
response, showImage, deleteImage, gameDone, gwendoTurn = "An AI error ocurred",False,False,False,False
self.bot.log("AI error (error code 1520)")
await ctx.channel.send(response)
self.bot.log(response,str(channelId))
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await ctx.channel.send(file = discord.File("resources/games/hexBoards/board"+str(channelId)+".png"))
if not gameDone:
with open("resources/games/oldImages/hex"+str(channelId), "w") as f:
f.write(str(oldImage.id))
if gameDone:
game = self.bot.database["hex games"].find_one({"_id":str(channelId)})
winner = game["winner"]
if winner != 0 and game["players"][0] != game["players"][1]: # player1 != player2
winnings = game["difficulty"]*10
self.bot.money.addMoney(game["players"][winner-1].lower(),winnings)
self.bot.databaseFuncs.deleteGame("hex games",str(channelId))

View File

@ -1,8 +1,7 @@
from .invest import Invest from .invest import Invest
from .trivia import Trivia from .trivia import Trivia
from .blackjack import Blackjack from .blackjack import Blackjack
from .connectFour import connectFour from .connectFour import ConnectFour
from .gameLoops import GameLoops
from .hangman import Hangman from .hangman import Hangman
from .hex import HexGame from .hex import HexGame
@ -13,7 +12,6 @@ class Games():
self.invest = Invest(bot) self.invest = Invest(bot)
self.trivia = Trivia(bot) self.trivia = Trivia(bot)
self.blackjack = Blackjack(bot) self.blackjack = Blackjack(bot)
self.connectFour = connectFour(bot) self.connectFour = ConnectFour(bot)
self.gameLoops = GameLoops(bot)
self.hangman = Hangman(bot) self.hangman = Hangman(bot)
self.hex = HexGame(bot) self.hex = HexGame(bot)

View File

@ -1,4 +1,4 @@
import json, urllib, datetime, string import json, urllib, datetime, string, discord
from .hangmanDraw import DrawHangman from .hangmanDraw import DrawHangman
@ -9,8 +9,13 @@ class Hangman():
self.bot = bot self.bot = bot
self.draw = DrawHangman(bot) self.draw = DrawHangman(bot)
def hangmanStart(self,channel,user): async def start(self, ctx):
await ctx.defer()
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
game = self.bot.database["hangman games"].find_one({"_id":channel}) game = self.bot.database["hangman games"].find_one({"_id":channel})
userName = self.bot.databaseFuncs.getName(user)
startedGame = False
if game == None: if game == None:
apiKey = self.bot.credentials.wordnikKey apiKey = self.bot.credentials.wordnikKey
@ -26,86 +31,135 @@ class Hangman():
remainingLetters = list(string.ascii_uppercase) remainingLetters = list(string.ascii_uppercase)
try: self.draw.drawImage(channel)
self.draw.drawImage(channel)
except: logMessage = "Game started"
self.bot.log("Error drawing image (error code 1710)") sendMessage = f"{userName} started game of hangman."
return f"{self.bot.databaseFuncs.getName(user)} started game of hangman.", True, False, remainingLetters startedGame = True
else: else:
return "There's already a Hangman game going on in the channel", False, False, [] logMessage = "There was already a game going on"
sendMessage = "There's already a Hangman game going on in the channel"
def hangmanStop(self,channel): self.bot.log(logMessage)
self.bot.database["hangman games"].delete_one({"_id":channel}) await ctx.send(sendMessage)
return "Game stopped.", False, False, [] if startedGame:
filePath = f"resources/games/hangmanBoards/hangmanBoard{channel}.png"
newImage = await ctx.channel.send(file = discord.File(filePath))
def hangmanGuess(self,channel,user,guess): blankMessage = await ctx.channel.send("_ _")
reactionMessages = {newImage : remainingLetters[:15], blankMessage : remainingLetters[15:]}
oldMessages = f"{newImage.id}\n{blankMessage.id}"
with open(f"resources/games/oldImages/hangman{channel}", "w") as f:
f.write(oldMessages)
for message, letters in reactionMessages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
async def stop(self, ctx):
channel = str(ctx.channel.id)
game = self.bot.database["hangman games"].find_one({"_id": channel})
if game is None:
await ctx.send("There's no game going on")
elif f"#{ctx.author.id}" != game["player"]:
await ctx.send("You can't end a game you're not in")
else:
self.bot.database["hangman games"].delete_one({"_id":channel})
with open(f"resources/games/oldImages/hangman{channel}", "r") as f:
messages = f.read().splitlines()
for message in messages:
oldMessage = await ctx.channel.fetch_message(int(message))
self.bot.log("Deleting old message")
await oldMessage.delete()
await ctx.send("Game stopped")
async def guess(self, message, user, guess):
channel = str(message.channel.id)
game = self.bot.database["hangman games"].find_one({"_id":channel}) game = self.bot.database["hangman games"].find_one({"_id":channel})
if game != None: gameExists = (game != None)
if user == game["player"]: singleLetter = (len(guess) == 1 and guess.isalpha())
if len(guess) == 1 and guess in list(string.ascii_uppercase): newGuess = (guess not in game["guessed letters"])
if guess not in game["guessed letters"]: validGuess = (gameExists and singleLetter and newGuess)
correctGuess = 0
for x, letter in enumerate(game["word"]): if validGuess:
if guess == letter: self.bot.log("Guessed the letter")
correctGuess += 1 correctGuess = 0
self.bot.database["hangman games"].update_one({"_id":channel},{"$set":{"guessed."+str(x):True}})
if correctGuess == 0: for x, letter in enumerate(game["word"]):
self.bot.database["hangman games"].update_one({"_id":channel},{"$inc":{"misses":1}}) if guess == letter:
correctGuess += 1
self.bot.database["hangman games"].update_one({"_id":channel},{"$set":{"guessed."+str(x):True}})
self.bot.database["hangman games"].update_one({"_id":channel},{"$push":{"guessed letters":guess}}) if correctGuess == 0:
self.bot.database["hangman games"].update_one({"_id":channel},{"$inc":{"misses":1}})
remainingLetters = list(string.ascii_uppercase) self.bot.database["hangman games"].update_one({"_id":channel},{"$push":{"guessed letters":guess}})
game = self.bot.database["hangman games"].find_one({"_id":channel}) remainingLetters = list(string.ascii_uppercase)
for letter in game["guessed letters"]: game = self.bot.database["hangman games"].find_one({"_id":channel})
remainingLetters.remove(letter)
if correctGuess == 1: for letter in game["guessed letters"]:
message = f"Guessed {guess}. There was 1 {guess} in the word." remainingLetters.remove(letter)
else:
message = f"Guessed {guess}. There were {correctGuess} {guess}s in the word."
try: if correctGuess == 1:
self.draw.drawImage(channel) sendMessage = f"Guessed {guess}. There was 1 {guess} in the word."
except:
self.bot.log("Error drawing image (error code 1710)")
if game["misses"] == 6:
self.hangmanStop(channel)
return message+" You've guessed wrong six times and have lost the game.", True, True, []
elif all(i == True for i in game["guessed"]):
self.hangmanStop(channel)
self.bot.money.addMoney(user,15)
return message+" You've guessed the word! Congratulations! Adding 15 GwendoBucks to your account", True, True, []
else:
return message, True, True, remainingLetters
else:
return f"You've already guessed {guess}", False, False, []
else:
return "", False, False, []
else: else:
return "", False, False, [] sendMessage = f"Guessed {guess}. There were {correctGuess} {guess}s in the word."
else:
return "There's no Hangman game going on in this channel", False, False, [] self.draw.drawImage(channel)
if game["misses"] == 6:
self.bot.database["hangman games"].delete_one({"_id":channel})
sendMessage += " You've guessed wrong six times and have lost the game."
remainingLetters = []
elif all(i == True for i in game["guessed"]):
self.bot.database["hangman games"].delete_one({"_id":channel})
self.bot.money.addMoney(user,15)
sendMessage += " You've guessed the word! Congratulations! Adding 15 GwendoBucks to your account"
remainingLetters = []
await message.channel.send(sendMessage)
with open(f"resources/games/oldImages/hangman{channel}", "r") as f:
oldMessageIDs = f.read().splitlines()
for oldID in oldMessageIDs:
oldMessage = await message.channel.fetch_message(int(oldID))
self.bot.log("Deleting old message")
await oldMessage.delete()
filePath = f"resources/games/hangmanBoards/hangmanBoard{channel}.png"
newImage = await message.channel.send(file = discord.File(filePath))
if len(remainingLetters) > 0:
if len(remainingLetters) > 15:
blankMessage = await message.channel.send("_ _")
reactionMessages = {newImage : remainingLetters[:15], blankMessage : remainingLetters[15:]}
else:
blankMessage = ""
reactionMessages = {newImage : remainingLetters}
if blankMessage != "":
oldMessages = f"{newImage.id}\n{blankMessage.id}"
else:
oldMessages = str(newImage.id)
with open(f"resources/games/oldImages/hangman{channel}", "w") as f:
f.write(oldMessages)
for message, letters in reactionMessages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
def parseHangman(self,channel,user,command):
if command == "start":
try:
return self.hangmanStart(channel,user)
except:
self.bot.log("Error starting game (error code 1730)")
elif command == "stop":
return self.hangmanStop(channel)
elif command.startswith("guess "):
guess = command[6:].upper()
try:
return self.hangmanGuess(channel,user,guess)
except:
self.bot.log("Error in guessing (Error Code 1720)")
else:
return "I didn't understand that", False, False, []

View File

@ -1,6 +1,7 @@
import random import random
import copy import copy
import math import math
import discord
from .hexDraw import DrawHex from .hexDraw import DrawHex
@ -13,102 +14,146 @@ for position in ALL_POSITIONS:
HEX_DIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)] HEX_DIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)]
class HexGame(): class HexGame():
def __init__(self,bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.draw = DrawHex(bot) self.draw = DrawHex(bot)
# Parses command async def surrender(self, ctx):
def parseHex(self, command, channel, user): channel = str(ctx.channel_id)
commands = command.lower().split()
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
if command == "" or command == " ": user = f"#{ctx.author.id}"
return "I didn't get that. Use \"/hex start [opponent]\" to start a game.", False, False, False, False players = game["players"]
elif commands[0] == "start":
# Starting a game
if len(commands) == 1: # if the commands is "/hex start", the opponent is Gwendolyn at difficulty 2
commands.append("2")
self.bot.log("Starting a hex game with hexStart(). "+str(user)+" challenged "+commands[1])
return self.hexStart(channel,user,commands[1]) # commands[1] is the opponent
# If using a command with no game, return error
elif game == None:
return "There's no game in this channel", False, False, False, False
# Stopping the game
elif commands[0] == "stop":
if user in game["players"]:
return "Ending game.", False, False, True, False
else:
return "You can't end a game where you're not a player.", False, False, False, False
# Placing a piece
elif commands[0] == "place":
try:
return self.placeHex(channel,commands[1], user)
except:
return "I didn't get that. To place a piece use \"/hex place [position]\". A valid position is e.g. \"E2\".", False, False, False, False
# Undo
elif commands[0] == "undo":
return self.undoHex(channel, user)
# Surrender
elif commands[0] == "surrender":
players = game["players"]
if user in players:
opponent = (players.index(user) + 1) % 2
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}})
return "{} surrendered. That means {} won! Adding 30 Gwendobucks to their account.".format(self.bot.databaseFuncs.getName(user),self.bot.databaseFuncs.getName(players[opponent])), False, False, True, False
else:
return "You can't surrender when you're not a player.", False, False, False, False
# Swap
elif commands[0] == "swap":
if len(game["gameHistory"]) == 1: # Only after the first move
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"players":game["players"][::-1]}}) # Swaps their player-number
# Swaps the color of the hexes on the board drawing:
self.draw.drawSwap(channel)
player2 = game["players"][1]
gwendoTurn = (player2 == "Gwendolyn")
return "The color of both players were swapped. It is now {}'s turn".format(player2), True, True, False, gwendoTurn
else:
return "You can only swap as the second player after the very first move.", False, False, False, False
if user not in players:
await ctx.send("You can't surrender when you're not a player.")
else: else:
return "I didn't get that. Use \"/hex start [opponent]\" to start a game, \"/hex place [position]\" to place a piece, \"/hex undo\" to undo your last move or \"/hex stop\" to stop a current game.", False, False, False, False opponent = (players.index(user) + 1) % 2
opponentName = self.bot.databaseFuncs.getName(players[opponent])
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}})
await ctx.send(f"{ctx.author.display_name} surrendered. That means {opponentName} won! Adding 30 Gwendobucks to their account")
with open(f"resources/games/oldImages/hex{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else:
self.bot.log("The old image was already deleted")
self.bot.log("Sending the image")
filePath = f"resources/games/hexBoards/board{channel}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id))
# Swap
async def swap(self, ctx):
channel = str(ctx.channel_id)
game = self.bot.database["hex games"].find_one({"_id":channel})
user = f"#{ctx.author.id}"
if game is None:
await ctx.send("You can't swap nothing")
elif user not in game["players"]:
await ctx.send("You're not in the game")
elif len(game["gameHistory"]) != 1: # Only after the first move
await ctx.send("You can only swap as the second player after the very first move.")
elif user != game["players"][game["turn"]-1]:
await ctx.send("You can only swap after your opponent has placed their piece")
else:
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"players":game["players"][::-1]}}) # Swaps their player-number
# Swaps the color of the hexes on the board drawing:
self.draw.drawSwap(channel)
opponent = game["players"][::-1][game["turn"]-1]
gwendoTurn = (opponent == f"#{self.bot.user.id}")
opponentName = self.bot.databaseFuncs.getName(opponent)
await ctx.send(f"The color of the players were swapped. It is now {opponentName}'s turn")
with open(f"resources/games/oldImages/hex{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else:
self.bot.log("The old image was already deleted")
self.bot.log("Sending the image")
filePath = f"resources/games/hexBoards/board{channel}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id))
if gwendoTurn:
await self.hexAI(ctx)
# Starts the game # Starts the game
def hexStart(self, channel, user, opponent): async def start(self, ctx, opponent):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
user = f"#{ctx.author.id}"
channel = str(ctx.channel_id)
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
if game == None: startedGame = False
if opponent in ["1","2","3","4","5"]: canStart = True
difficulty = int(opponent)
diffText = " with difficulty "+opponent
opponent = "Gwendolyn"
elif opponent.lower() == "gwendolyn":
difficulty = 2
diffText = " with difficulty 2"
opponent = "Gwendolyn"
else:
try:
int(opponent)
return "That difficulty doesn't exist", False, False, False, False
except:
opponent = self.bot.databaseFuncs.getID(opponent)
if opponent == None:
return "I can't find that user", False, False, False, False
else:
# Opponent is another player
difficulty = 3
diffText = ""
if game != None:
sendMessage = "There's already a hex game going on in this channel"
logMessage = "There was already a game going on"
canStart = False
else:
if type(opponent) == int:
# Opponent is Gwendolyn
if opponent in range(1, 6):
opponentName = "Gwendolyn"
difficulty = int(opponent)
diffText = f" with difficulty {difficulty}"
opponent = f"#{self.bot.user.id}"
else:
sendMessage = "Difficulty doesn't exist"
logMessage = "They tried to play against a difficulty that doesn't exist"
canStart = False
elif type(opponent) == discord.member.Member:
if opponent.bot:
# User has challenged a bot
if opponent == self.bot.user:
# It was Gwendolyn
opponentName = "Gwendolyn"
difficulty = 2
diffText = f" with difficulty {difficulty}"
opponent = f"#{self.bot.user.id}"
else:
sendMessage = "You can't challenge a bot!"
logMessage = "They tried to challenge a bot"
canStart = False
else:
# Opponent is another player
if ctx.author != opponent:
opponentName = opponent.display_name
opponent = f"#{opponent.id}"
difficulty = 5
diffText = ""
else:
sendMessage = "You can't play against yourself"
logMessage = "They tried to play against themself"
canStart = False
else:
canStart = False
logMessage = f"Opponent was neither int or member. It was {type(opponent)}"
sendMessage = "Something went wrong"
if canStart:
# board is 11x11 # board is 11x11
board = [ [ 0 for i in range(BOARDWIDTH) ] for j in range(BOARDWIDTH) ] board = [[0 for i in range(BOARDWIDTH)] for j in range(BOARDWIDTH)]
players = [user,opponent] players = [user, opponent]
random.shuffle(players) # random starting player random.shuffle(players) # random starting player
gameHistory = [] gameHistory = []
@ -120,137 +165,196 @@ class HexGame():
# draw the board # draw the board
self.draw.drawBoard(channel) self.draw.drawBoard(channel)
gwendoTurn = True if players[0] == "Gwendolyn" else False gwendoTurn = (players[0] == f"#{self.bot.user.id}")
showImage = True startedGame = True
return "Started Hex game against "+self.bot.databaseFuncs.getName(opponent)+ diffText+". It's "+self.bot.databaseFuncs.getName(players[0])+"'s turn", showImage, False, False, gwendoTurn
else: turnName = self.bot.databaseFuncs.getName(players[0])
return "There's already a hex game going on in this channel", False, False, False, False sendMessage = f"Started Hex game against {opponentName}{diffText}. It's {turnName}'s turn"
logMessage = "Game started"
await ctx.send(sendMessage)
self.bot.log(logMessage)
if startedGame:
filePath = f"resources/games/hexBoards/board{ctx.channel_id}.png"
newImage = await ctx.channel.send(file = discord.File(filePath))
with open(f"resources/games/oldImages/hex{ctx.channel_id}", "w") as f:
f.write(str(newImage.id))
if gwendoTurn:
await self.hexAI(ctx)
# Places a piece at the given location and checks things afterwards # Places a piece at the given location and checks things afterwards
def placeHex(self, channel : str,position : str, user): async def placeHex(self, ctx, position : str, user):
channel = str(ctx.channel_id)
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
placedPiece = False
if game != None: if game == None:
players = game["players"] sendMessage = "There's no game in this channel"
if user in players: self.bot.log("There was no game going on")
turn = game["turn"] elif not (position[0].isalpha() and position[1:].isnumeric() and len(position) in [2, 3]):
if players[0] == players[1]: sendMessage = "The position must be a letter followed by a number."
player = turn self.bot.log(f"The position was not valid, {position}")
else:
player = players.index(user)+1
if player == turn:
board = game["board"]
self.bot.log("Placing a piece on the board with placeHex()")
# Places on board
board = self.placeOnHexBoard(board,player,position)
if isinstance(board, list):
# If the move is valid:
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"board":board}})
turn = 1 if turn == 2 else 2
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"turn":turn}})
# Checking for a win
self.bot.log("Checking for win")
winner = self.evaluateBoard(game["board"])[1]
if winner == 0: # Continue with the game.
gameWon = False
message = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+". It's now "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn."# The score is "+str(score)
else: # Congratulations!
gameWon = True
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":winner}})
message = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+" and won!"
if game["players"][winner-1] != "Gwendolyn":
winAmount = game["difficulty"]*10
message += " Adding "+str(winAmount)+" GwendoBucks to their account."
self.bot.database["hex games"].update_one({"_id":channel},
{"$push":{"gameHistory":(int(position[1])-1, ord(position[0])-97)}})
# Is it now Gwendolyn's turn?
gwendoTurn = False
if game["players"][turn-1] == "Gwendolyn":
self.bot.log("It's Gwendolyn's turn")
gwendoTurn = True
# Update the board
self.draw.drawHexPlacement(channel,player,position)
return message, True, True, gameWon, gwendoTurn
else:
# Invalid move. "board" is the error message
message = board
return message, False, False, False, False
else:
# Move out of turn
message = "It isn't your turn, it is "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn."
return message, False, False, False, False
else:
message = "You can't place when you're not in the game. The game's players are: "+self.bot.databaseFuncs.getName(game["players"][0])+" and "+self.bot.databaseFuncs.getName(game["players"][1])+"."
return message, False, False, False, False
else: else:
return "There's no game in this channel", False, False, False, False players = game["players"]
if user not in players:
sendMessage = f"You can't place when you're not in the game. The game's players are: {self.bot.databaseFuncs.getName(game['players'][0])} and {self.bot.databaseFuncs.getName(game['players'][1])}."
self.bot.log("They aren't in the game")
elif players[game["turn"]-1] != user:
sendMessage = "It's not your turn"
self.bot.log("It wasn't their turn")
else:
player = game["turn"]
turn = game["turn"]
board = game["board"]
self.bot.log("Placing a piece on the board with placeHex()")
# Places on board
board = self.placeOnHexBoard(board,player,position)
if board is None:
self.bot.log("It was an invalid position")
sendMessage = ("That's an invalid position. You must place your piece on an empty field.")
else:
# If the move is valid:
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"board":board}})
turn = (turn % 2) + 1
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"turn":turn}})
# Checking for a win
self.bot.log("Checking for win")
winner = self.evaluateBoard(game["board"])[1]
if winner == 0: # Continue with the game.
gameWon = False
sendMessage = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+". It's now "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn."# The score is "+str(score)
else: # Congratulations!
gameWon = True
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":winner}})
sendMessage = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+" and won!"
if game["players"][winner-1] != f"#{self.bot.user.id}":
winAmount = game["difficulty"]*10
sendMessage += " Adding "+str(winAmount)+" GwendoBucks to their account."
self.bot.database["hex games"].update_one({"_id":channel},
{"$push":{"gameHistory":(int(position[1])-1, ord(position[0])-97)}})
# Is it now Gwendolyn's turn?
gwendoTurn = False
if game["players"][turn-1] == f"#{self.bot.user.id}":
self.bot.log("It's Gwendolyn's turn")
gwendoTurn = True
placedPiece = True
if user == f"#{self.bot.user.id}":
await ctx.channel.send(sendMessage)
else:
await ctx.send(sendMessage)
if placedPiece:
# Update the board
self.draw.drawHexPlacement(channel,player, position)
with open(f"resources/games/oldImages/hex{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else:
self.bot.log("The old image was already deleted")
self.bot.log("Sending the image")
filePath = f"resources/games/hexBoards/board{channel}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
if gameWon:
self.bot.log("Dealing with the winning player")
game = self.bot.database["hex games"].find_one({"_id":channel})
winner = game["winner"]
if game["players"][winner-1] != f"#{self.bot.user.id}":
winnings = game["difficulty"]*10
self.bot.money.addMoney(game["players"][winner-1].lower(),winnings)
else:
with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id))
if gwendoTurn:
await self.hexAI(ctx)
# Returns a board where the placement has ocurred # Returns a board where the placement has ocurred
def placeOnHexBoard(self, board,player,position): def placeOnHexBoard(self, board,player,position):
# Translates the position # Translates the position
position = position.lower() position = position.lower()
# Error handling # Error handling
try: column = ord(position[0]) - 97 # ord() translates from letter to number
column = ord(position[0]) - 97 # ord() translates from letter to number row = int(position[1:]) - 1
row = int(position[1:]) - 1 if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH):
if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH): self.bot.log("Position out of bounds")
self.bot.log("Position out of bounds (error code 1533)") return None
return "Error. That position is out of bounds."
except:
self.bot.log("Invalid position (error code 1531)")
return "Error. The position should be a letter followed by a number, e.g. \"e2\"."
# Place at the position # Place at the position
if board[row][column] == 0: if board[row][column] == 0:
board[row][column] = player board[row][column] = player
return board return board
else: else:
self.bot.log("Cannot place on existing piece (error code 1532)") self.bot.log("Cannot place on existing piece (error code 1532)")
return "Error. You must place on an empty space." return None
# After your move, you have the option to undo get your turn back #TimeTravel # After your move, you have the option to undo get your turn back #TimeTravel
def undoHex(self, channel, user): async def undo(self, ctx):
channel = str(ctx.channel_id)
user = f"#{ctx.author.id}"
undid = False
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
if user in game["players"]: if user not in game["players"]:
if len(game["gameHistory"]): sendMessage = "You're not a player in the game"
turn = game["turn"] elif len(game["gameHistory"]) == 0:
# You can only undo after your turn, which is the opponent's turn. sendMessage = "You can't undo nothing"
if user == game["players"][(turn % 2)]: # If it's not your turn elif user != game["players"][(game["turn"] % 2)]: # If it's not your turn
self.bot.log("Undoing {}'s last move".format(self.bot.databaseFuncs.getName(user))) sendMessage = "It's not your turn"
lastMove = game["gameHistory"].pop()
game["board"][lastMove[0]][lastMove[1]] = 0
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"board":game["board"]}})
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"turn":turn%2 + 1}})
# Update the board
self.draw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear
return "You undid your last move at {}".format(lastMove), True, True, False, False
else:
# Sassy
return "Nice try. You can't undo your opponent's move. ", False, False, False, False
else:
# Sassy
return "Really? You undo right at the start of the game?", False, False, False, False
else: else:
return "You're not a player in the game", False, False, False, False turn = game["turn"]
self.bot.log("Undoing {}'s last move".format(self.bot.databaseFuncs.getName(user)))
lastMove = game["gameHistory"].pop()
game["board"][lastMove[0]][lastMove[1]] = 0
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"board":game["board"]}})
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"turn":turn%2 + 1}})
# Update the board
self.draw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear
sendMessage = f"You undid your last move at {lastMove}"
undid = True
await ctx.send(sendMessage)
if undid:
with open(f"resources/games/oldImages/hex{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read()))
if oldImage is not None:
await oldImage.delete()
else:
self.bot.log("The old image was already deleted")
self.bot.log("Sending the image")
filePath = f"resources/games/hexBoards/board{channel}.png"
oldImage = await ctx.channel.send(file = discord.File(filePath))
with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id))
# Plays as the AI # Plays as the AI
def hexAI(self, channel): async def hexAI(self, ctx):
channel = str(ctx.channel_id)
self.bot.log("Figuring out best move") self.bot.log("Figuring out best move")
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
board = game["board"] board = game["board"]
@ -269,32 +373,10 @@ class HexGame():
moves.remove(move) moves.remove(move)
chosenMove = random.choice(moves) chosenMove = random.choice(moves)
"""
GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue
if len(data[channel]["gameHistory"]) == 0:
return placeHex(channel,"F6", "Gwendolyn") # If starting, start in the middle
board = data[channel]["board"]
difficulty = data[channel]["difficulty"]
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
judgements = [float('nan')]*len(possiblePlaces) # All possible moves are yet to be judged
current_score = evaluateBoard(board)[0]
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = GwenColor
if evaluateBoard(testBoard)[0] != current_score: # only think about a move if it improves the score (it's impossible to get worse)
# Testing a move and evaluating it
judgements[i] = minimaxHex(testBoard,difficulty,-math.inf,math.inf,GwenColor==2)
self.bot.log("Best score for place {} is {}".format((i // BOARDWIDTH,i % BOARDWIDTH),judgements[i]))
bestScore = max(judgements) if (GwenColor == 1) else min(judgements) # this line has an error
indices = [i for i, x in enumerate(judgements) if x == bestScore] # which moves got that score?
i = random.choice(indices)
chosenMove = (i // BOARDWIDTH , i % BOARDWIDTH)
"""
placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1) placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1)
self.bot.log("ChosenMove is {} at {}".format(chosenMove,placement)) self.bot.log(f"ChosenMove is {chosenMove} at {placement}")
return self.placeHex(channel,placement, "Gwendolyn")
await self.placeHex(ctx, placement, f"#{self.bot.user.id}")
def evaluateBoard(self, board): def evaluateBoard(self, board):

View File

@ -122,7 +122,7 @@ class DrawHex():
def drawHexPlacement(self, channel,player,position): def drawHexPlacement(self, channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png" FILEPATH = "resources/games/hexBoards/board"+channel+".png"
self.bot.log("Drawing a newly placed hex. Filepath: "+FILEPATH) self.bot.log(f"Drawing a newly placed hex. Filename: board{channel}.png")
# Translates position # Translates position
# We don't need to error-check, because the position is already checked in placeOnHexBoard() # We don't need to error-check, because the position is already checked in placeOnHexBoard()

View File

@ -1,3 +1,5 @@
import discord
class Invest(): class Invest():
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -103,35 +105,48 @@ class Invest():
else: else:
return "no" return "no"
def parseInvest(self, content: str, user : str): async def parseInvest(self, ctx, parameters):
if content.startswith("check"): try:
commands = content.split(" ") await ctx.defer()
except:
self.bot.log("Defer failed")
user = f"#{ctx.author.id}"
if parameters.startswith("check"):
commands = parameters.split(" ")
if len(commands) == 1: if len(commands) == 1:
return self.getPortfolio(user) response = self.getPortfolio(user)
else: else:
price = self.getPrice(commands[1]) price = self.getPrice(commands[1])
if price == 0: if price == 0:
return f"{commands[1].upper()} is not traded on the american market." response = f"{commands[1].upper()} is not traded on the american market."
else: else:
price = f"{price:,}".replace(",",".") price = f"{price:,}".replace(",",".")
return f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks" response = f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks"
elif content.startswith("buy"): elif parameters.startswith("buy"):
commands = content.split(" ") commands = parameters.split(" ")
if len(commands) == 3: if len(commands) == 3:
#try: response = self.buyStock(user,commands[1],int(commands[2]))
return self.buyStock(user,commands[1],int(commands[2]))
#except:
# return "The command must be given as \"/invest buy [stock] [amount of GwendoBucks to purchase with]\""
else: else:
return "You must give both a stock name and an amount of gwendobucks you wish to spend." response = "You must give both a stock name and an amount of gwendobucks you wish to spend."
elif content.startswith("sell"): elif parameters.startswith("sell"):
commands = content.split(" ") commands = parameters.split(" ")
if len(commands) == 3: if len(commands) == 3:
try: try:
return self.sellStock(user,commands[1],int(commands[2])) response = self.sellStock(user,commands[1],int(commands[2]))
except: except:
return "The command must be given as \"/invest sell [stock] [amount of GwendoBucks to sell stocks for]\"" response = "The command must be given as \"/invest sell [stock] [amount of GwendoBucks to sell stocks for]\""
else: else:
return "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for." response = "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for."
else:
response = "Incorrect parameters"
if response.startswith("**"):
responses = response.split("\n")
em = discord.Embed(title=responses[0],description="\n".join(responses[1:]),colour=0x00FF00)
await ctx.send(embed=em)
else:
await ctx.send(response)

View File

@ -14,6 +14,15 @@ class Money():
return userData["money"] return userData["money"]
else: return 0 else: return 0
async def sendBalance(self, ctx):
await ctx.defer()
response = self.checkBalance("#"+str(ctx.author.id))
if response == 1:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBuck"
else:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBucks"
await ctx.send(new_message)
# Adds money to the account of a user # Adds money to the account of a user
def addMoney(self,user,amount): def addMoney(self,user,amount):
self.bot.log("adding "+str(amount)+" to "+user+"'s account") self.bot.log("adding "+str(amount)+" to "+user+"'s account")
@ -26,26 +35,39 @@ class Money():
self.database["users"].insert_one({"_id":user,"user name":self.bot.databaseFuncs.getName(user),"money":amount}) self.database["users"].insert_one({"_id":user,"user name":self.bot.databaseFuncs.getName(user),"money":amount})
# Transfers money from one user to another # Transfers money from one user to another
def giveMoney(self,user,targetUser,amount): async def giveMoney(self, ctx, user, amount):
userData = self.database["users"].find_one({"_id":user}) try:
targetUser = self.bot.databaseFuncs.getID(targetUser) await ctx.defer()
except:
self.bot.log("Defer failed")
username = user.display_name
if self.bot.databaseFuncs.getID(username) == None:
async for member in ctx.guild.fetch_members(limit=None):
if member.display_name.lower() == username.lower():
username = member.display_name
userID = "#" + str(member.id)
newUser = {"_id":userID,"user name":username,"money":0}
self.bot.database["users"].insert_one(newUser)
userData = self.database["users"].find_one({"_id":f"#{ctx.author.id}"})
targetUser = self.bot.databaseFuncs.getID(username)
if amount > 0: if amount > 0:
if targetUser != None: if targetUser != None:
if userData != None: if userData != None:
if userData["money"] >= amount: if userData["money"] >= amount:
self.addMoney(user,-1 * amount) self.addMoney(f"#{ctx.author.id}",-1 * amount)
self.addMoney(targetUser,amount) self.addMoney(targetUser,amount)
return "Transferred "+str(amount)+" GwendoBucks to "+self.bot.databaseFuncs.getName(targetUser) await ctx.send(f"Transferred {amount} GwendoBucks to {username}")
else: else:
self.bot.log("They didn't have enough GwendoBucks (error code 1223b)") self.bot.log("They didn't have enough GwendoBucks")
return "You don't have that many GwendoBucks (error code 1223b)" await ctx.send("You don't have that many GwendoBucks")
else: else:
self.bot.log("They didn't have enough GwendoBucks (error code 1223a)") self.bot.log("They didn't have enough GwendoBucks")
return "You don't have that many GwendoBucks (error code 1223a)" await ctx.send("You don't have that many GwendoBuck")
else: else:
self.bot.log("They weren't in the system") self.bot.log("They weren't in the system")
return "The target doesn't exist" await ctx.send("The target doesn't exist")
else: else:
self.bot.log("They tried to steal") self.bot.log("They tried to steal")
return "Yeah, no. You can't do that" await ctx.send("Yeah, no. You can't do that")

View File

@ -1,6 +1,7 @@
import json import json
import urllib import urllib
import random import random
import asyncio
class Trivia(): class Trivia():
def __init__(self, bot): def __init__(self, bot):
@ -83,3 +84,38 @@ class Trivia():
self.bot.log("Couldn't find the question (error code 1102)") self.bot.log("Couldn't find the question (error code 1102)")
return None return None
async def triviaParse(self, ctx, answer):
try:
await ctx.defer()
except:
self.bot.log("defer failed")
if answer == "":
question, options, correctAnswer = self.triviaStart(str(ctx.channel_id))
if options != "":
results = "**"+question+"**\n"
for x, option in enumerate(options):
results += chr(x+97) + ") "+option+"\n"
await ctx.send(results)
await asyncio.sleep(60)
self.triviaCountPoints(str(ctx.channel_id))
self.bot.databaseFuncs.deleteGame("trivia questions",str(ctx.channel_id))
self.bot.log("Time's up for the trivia question",str(ctx.channel_id))
await ctx.send("Time's up The answer was \"*"+chr(correctAnswer)+") "+options[correctAnswer-97]+"*\". Anyone who answered that has gotten 1 GwendoBuck")
else:
await ctx.send(question, hidden=True)
elif answer in ["a","b","c","d"]:
response = self.triviaAnswer("#"+str(ctx.author.id), str(ctx.channel_id), answer)
if response.startswith("Locked in "):
await ctx.send(f"{ctx.author.display_name} answered **{answer}**")
else:
await ctx.send(response)
else:
self.bot.log("I didn't understand that (error code 1101)",str(ctx.channel_id))
await ctx.send("I didn't understand that (error code 1101)")

View File

@ -1,5 +1,6 @@
import math import math
import json import json
import discord
from utils import cap from utils import cap
@ -18,27 +19,28 @@ class LookupFuncs():
return(str(mods)) return(str(mods))
# Looks up a monster # Looks up a monster
def monsterFunc(self, command): async def monsterFunc(self, ctx, query):
self.bot.log("Looking up "+command) query = cap(query)
self.bot.log("Looking up "+query)
# 1-letter monsters don't exist # 1-letter monsters don't exist
if len(command) < 2: if len(query) < 2:
self.bot.log("Monster name too short (error code 601)") self.bot.log("Monster name too short")
return("I don't know that monster... (error code 601)","","","","","") await ctx.send("I don't know that monster...")
else: else:
# Opens "monsters.json" # Opens "monsters.json"
data = json.load(open('resources/lookup/monsters.json', encoding = "utf8")) data = json.load(open('resources/lookup/monsters.json', encoding = "utf8"))
for monster in data: for monster in data:
if "name" in monster and str(command) == monster["name"]: if "name" in monster and str(query) == monster["name"]:
self.bot.log("Found it!") self.bot.log("Found it!")
# Looks at the information about the monster and returns that information # Looks at the information about the monster and returns that information
# in separate variables, allowing Gwendolyn to know where to separate # in separate variables, allowing Gwendolyn to know where to separate
# the messages # the messages
if monster["subtype"] != "": if monster["subtype"] != "":
typs = (monster["type"]+" ("+monster["subtype"]+")") types = (monster["type"]+" ("+monster["subtype"]+")")
else: else:
typs = monster["type"] types = monster["type"]
con_mod = math.floor((monster["constitution"]-10)/2) con_mod = math.floor((monster["constitution"]-10)/2)
hit_dice = monster["hit_dice"] hit_dice = monster["hit_dice"]
@ -80,10 +82,10 @@ class LookupFuncs():
if c_immunities != "": if c_immunities != "":
c_immunities = "\n**Condition Immunities** "+c_immunities c_immunities = "\n**Condition Immunities** "+c_immunities
spec_ab = "" specialAbilities = ""
if "special_abilities" in monster: if "special_abilities" in monster:
for ability in monster["special_abilities"]: for ability in monster["special_abilities"]:
spec_ab += "\n\n***"+ability["name"]+".*** "+ability["desc"] specialAbilities += "\n\n***"+ability["name"]+".*** "+ability["desc"]
act = "" act = ""
if "actions" in monster: if "actions" in monster:
@ -95,10 +97,10 @@ class LookupFuncs():
for reaction in monster["reactions"]: for reaction in monster["reactions"]:
react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"] react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"]
leg_act = "" legendaryActions = ""
if "legendary_actions" in monster: if "legendary_actions" in monster:
for action in monster["legendary_actions"]: for action in monster["legendary_actions"]:
leg_act += "\n\n***"+action["name"]+".*** "+action["desc"] legendaryActions += "\n\n***"+action["name"]+".*** "+action["desc"]
if con_mod < 0: if con_mod < 0:
hit_dice += (" - "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])*(-1))) hit_dice += (" - "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])*(-1)))
@ -107,33 +109,56 @@ class LookupFuncs():
new_part = "\n--------------------" new_part = "\n--------------------"
monster_type = monster["size"]+" "+typs+", "+monster["alignment"]+"*" monster_type = monster["size"]+" "+types+", "+monster["alignment"]+"*"
basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n" basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n"
text1 = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"]) info = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"])
text2 = (spec_ab) monsterInfo = [(info, query),
text3 = (act) (specialAbilities, "Special Abilities"),
text4 = (react) (act, "Actions"),
text5 = (leg_act) (react, "Reactions"),
(legendaryActions, "Legendary Actions")]
self.bot.log("Returning monster information") self.bot.log("Returning monster information")
return(str(command),text1,text2,text3,text4,text5)
self.bot.log("Monster not in database (error code 602)") # Sends the received information. Separates into separate messages if
return("I don't know that monster... (error code 602)","","","","","") # there is too much text
await ctx.send(f"Result for \"{query}\"")
for text, title in monsterInfo:
if text != "":
if len(text) < 2000:
em = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.channel.send(embed = em)
else:
index = text[:2000].rfind(".")+1
em1 = discord.Embed(title = title, description = text[:index], colour=0xDEADBF)
await ctx.channel.send(embed = em1)
em2 = discord.Embed(title = "", description = text[index+1:], colour=0xDEADBF)
await ctx.channel.send(embed = em2)
break
else:
self.bot.log("Monster not in database")
await ctx.send("I don't know that monster...")
# Looks up a spell # Looks up a spell
def spellFunc(self, command): async def spellFunc(self, ctx, query):
self.bot.log("Looking up "+command) query = cap(query)
self.bot.log("Looking up "+query)
# Opens "spells.json" # Opens "spells.json"
data = json.load(open('resources/lookup/spells.json', encoding = "utf8")) data = json.load(open('resources/lookup/spells.json', encoding = "utf8"))
if str(command) in data: if query in data:
self.bot.log("Returning spell information") self.bot.log("Returning spell information")
spell_output = ("***"+str(command)+"***\n*"+str(data[str(command)]["level"])+" level "+str(data[str(command)]["school"])+"\nCasting Time: "+str(data[str(command)]["casting_time"])+"\nRange: "+str(data[str(command)]["range"])+"\nComponents: "+str(data[str(command)]["components"])+"\nDuration: "+str(data[str(command)]["duration"])+"*\n \n"+str(data[str(command)]["description"])) sendMessage = (f"***{query}***\n*{data[query]['level']} level {data[query]['school']}\nCasting Time: {data[query]['casting_time']}\nRange:{data[query]['range']}\nComponents:{data[query]['components']}\nDuration:{data[query]['duration']}*\n \n{data[query]['description']}")
else: else:
self.bot.log("I don't know that spell (error code 501)") self.bot.log("I don't know that spell (error code 501)")
spell_output = "I don't think that's a spell (error code 501)" sendMessage = "I don't think that's a spell (error code 501)"
self.bot.log("Successfully ran /spell")
return(spell_output) if len(sendMessage) > 2000:
await ctx.send(sendMessage[:2000])
await ctx.send(sendMessage[2000:])
else:
await ctx.send(sendMessage)

View File

@ -13,6 +13,8 @@ class BedreNetflix():
#Returns a list of no more than 5 options when user requests a movie #Returns a list of no more than 5 options when user requests a movie
async def requestMovie(self, ctx, movieName): async def requestMovie(self, ctx, movieName):
await ctx.defer()
self.bot.log("Searching for "+movieName) self.bot.log("Searching for "+movieName)
movieList = imdb.IMDb().search_movie(movieName) movieList = imdb.IMDb().search_movie(movieName)
movies = [] movies = []
@ -89,6 +91,8 @@ class BedreNetflix():
#Returns a list of no more than 5 options when user requests a show #Returns a list of no more than 5 options when user requests a show
async def requestShow(self, ctx, showName): async def requestShow(self, ctx, showName):
await ctx.defer()
self.bot.log("Searching for "+showName) self.bot.log("Searching for "+showName)
movies = imdb.IMDb().search_movie(showName) #Replace with tvdb movies = imdb.IMDb().search_movie(showName) #Replace with tvdb
shows = [] shows = []
@ -301,6 +305,8 @@ class BedreNetflix():
await ctx.send("```"+messageText[:cutOffIndex]+"```") await ctx.send("```"+messageText[:cutOffIndex]+"```")
await SendLongMessage(ctx,messageText[cutOffIndex+1:]) await SendLongMessage(ctx,messageText[cutOffIndex+1:])
await ctx.defer()
# showDM, showMovies, showShows, episodes # showDM, showMovies, showShows, episodes
params = [False, False, False, False] params = [False, False, False, False]
showDMArgs = ["d", "dm", "downloading", "downloadmanager"] showDMArgs = ["d", "dm", "downloading", "downloadmanager"]

View File

@ -15,7 +15,7 @@ class Generators():
yield (corpus[i], corpus[i+1], corpus[i+2]) yield (corpus[i], corpus[i+1], corpus[i+2])
# Generates a random name # Generates a random name
def nameGen(self): async def nameGen(self, ctx):
# Makes a list of all names from "names.txt" # Makes a list of all names from "names.txt"
names = open('resources/names.txt', encoding='utf8').read() names = open('resources/names.txt', encoding='utf8').read()
corpus = list(names) corpus = list(names)
@ -74,11 +74,12 @@ class Generators():
done = True done = True
genName = "".join(chain) genName = "".join(chain)
self.bot.log("Generated "+genName[:-1]) self.bot.log("Generated "+genName[:-1])
# Returns the name # Returns the name
return(genName) await ctx.send(genName)
# Generates a random tavern name # Generates a random tavern name
def tavernGen(self): async def tavernGen(self, ctx):
# Lists first parts, second parts and third parts of tavern names # Lists first parts, second parts and third parts of tavern names
fp = ["The Silver","The Golden","The Staggering","The Laughing","The Prancing","The Gilded","The Running","The Howling","The Slaughtered","The Leering","The Drunken","The Leaping","The Roaring","The Frowning","The Lonely","The Wandering","The Mysterious","The Barking","The Black","The Gleaming","The Tap-Dancing","The Sad","The Sexy","The Artificial","The Groovy","The Merciful","The Confused","The Pouting","The Horny","The Okay","The Friendly","The Hungry","The Handicapped","The Fire-breathing","The One-Eyed","The Psychotic","The Mad","The Evil","The Idiotic","The Trusty","The Busty"] fp = ["The Silver","The Golden","The Staggering","The Laughing","The Prancing","The Gilded","The Running","The Howling","The Slaughtered","The Leering","The Drunken","The Leaping","The Roaring","The Frowning","The Lonely","The Wandering","The Mysterious","The Barking","The Black","The Gleaming","The Tap-Dancing","The Sad","The Sexy","The Artificial","The Groovy","The Merciful","The Confused","The Pouting","The Horny","The Okay","The Friendly","The Hungry","The Handicapped","The Fire-breathing","The One-Eyed","The Psychotic","The Mad","The Evil","The Idiotic","The Trusty","The Busty"]
sp = ["Eel","Dolphin","Dwarf","Pegasus","Pony","Rose","Stag","Wolf","Lamb","Demon","Goat","Spirit","Horde","Jester","Mountain","Eagle","Satyr","Dog","Spider","Star","Dad","Rat","Jeremy","Mouse","Unicorn","Pearl","Ant","Crab","Penguin","Octopus","Lawyer","Ghost","Toad","Handjob","Immigrant","SJW","Dragon","Bard","Sphinx","Soldier","Salmon","Owlbear","Kite","Frost Giant","Arsonist"] sp = ["Eel","Dolphin","Dwarf","Pegasus","Pony","Rose","Stag","Wolf","Lamb","Demon","Goat","Spirit","Horde","Jester","Mountain","Eagle","Satyr","Dog","Spider","Star","Dad","Rat","Jeremy","Mouse","Unicorn","Pearl","Ant","Crab","Penguin","Octopus","Lawyer","Ghost","Toad","Handjob","Immigrant","SJW","Dragon","Bard","Sphinx","Soldier","Salmon","Owlbear","Kite","Frost Giant","Arsonist"]
@ -89,4 +90,4 @@ class Generators():
self.bot.log("Generated "+genTav) self.bot.log("Generated "+genTav)
# Return the name # Return the name
return(genTav) await ctx.send(genTav)

View File

@ -10,6 +10,8 @@ from .bedreNetflix import BedreNetflix
from .nerdShit import NerdShit from .nerdShit import NerdShit
from .generators import Generators from .generators import Generators
from utils import cap
class MyStringifier(d20.MarkdownStringifier): class MyStringifier(d20.MarkdownStringifier):
def _str_expression(self, node): def _str_expression(self, node):
if node.comment == None: if node.comment == None:
@ -57,29 +59,31 @@ class Other():
await ctx.send(embed = embed) await ctx.send(embed = embed)
# Responds with a greeting of a time-appropriate maner # Responds with a greeting of a time-appropriate maner
def helloFunc(self, author): async def helloFunc(self, ctx):
def time_in_range(start, end, x): 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: if start <= end:
return start <= x <= end return start <= x <= end
else: else:
return start <= x or x <= end return start <= x or x <= end
author = ctx.author.display_name
now = datetime.datetime.now() now = datetime.datetime.now()
if time_in_range(now.replace(hour=5, minute=0, second=0, microsecond=0),now.replace(hour=10, minute=0, second=0, microsecond=0), now): if time_in_range(now.replace(hour=5, minute=0, second=0, microsecond=0),now.replace(hour=10, minute=0, second=0, microsecond=0), now):
return("Good morning, "+str(author)) sendMessage = "Good morning, "+str(author)
elif time_in_range(now.replace(hour=10, minute=0, second=0, microsecond=0),now.replace(hour=13, minute=0, second=0, microsecond=0), now):
return("Good day, "+str(author))
elif time_in_range(now.replace(hour=13, minute=0, second=0, microsecond=0),now.replace(hour=18, minute=0, second=0, microsecond=0), now): elif time_in_range(now.replace(hour=13, minute=0, second=0, microsecond=0),now.replace(hour=18, minute=0, second=0, microsecond=0), now):
return("Good afternoon, "+str(author)) sendMessage = "Good afternoon, "+str(author)
elif time_in_range(now.replace(hour=18, minute=0, second=0, microsecond=0),now.replace(hour=22, minute=0, second=0, microsecond=0), now): elif time_in_range(now.replace(hour=18, minute=0, second=0, microsecond=0),now.replace(hour=22, minute=0, second=0, microsecond=0), now):
return("Good evening, "+str(author)) sendMessage = "Good evening, "+str(author)
elif time_in_range(now.replace(hour=22, minute=0, second=0, microsecond=0),now.replace(hour=23, minute=59, second=59, microsecond=0), now): elif time_in_range(now.replace(hour=22, minute=0, second=0, microsecond=0),now.replace(hour=23, minute=59, second=59, microsecond=0), now):
return("Good night, "+str(author)) sendMessage = "Good night, "+str(author)
else: else:
return("Hello, "+str(author)) sendMessage = "Hello, "+str(author)
await ctx.send(sendMessage)
# Finds a random picture online # Finds a random picture online
def imageFunc(self): async def imageFunc(self, ctx):
# Picks a type of camera, which decides the naming scheme # Picks a type of camera, which decides the naming scheme
cams = ("one","two","three","four") cams = ("one","two","three","four")
cam = random.choice(cams) cam = random.choice(cams)
@ -113,22 +117,31 @@ class Other():
tree = lxml.etree.HTML(read) tree = lxml.etree.HTML(read)
images = tree.xpath('//a[@class = "thumb"]/@href') images = tree.xpath('//a[@class = "thumb"]/@href')
# Picks an image if len(images) == 0:
number = random.randint(1,len(images))-1 await ctx.send("Found no images")
image = images[number] else:
# Picks an image
number = random.randint(1,len(images))-1
image = images[number]
self.bot.log("Picked image number "+str(number)) self.bot.log("Picked image number "+str(number))
# Returns the image # Returns the image
self.bot.log("Successfully returned an image") self.bot.log("Successfully returned an image")
return(image)
await ctx.send(image)
# Finds a page from the Senkulpa Wikia # Finds a page from the Senkulpa Wikia
def findWikiPage(self, search : str): async def findWikiPage(self, ctx, search : str):
await ctx.defer()
search = cap(search)
foundPage = False
self.bot.log("Trying to find wiki page for "+search) self.bot.log("Trying to find wiki page for "+search)
wikia.set_lang("da") wikia.set_lang("da")
searchResults = wikia.search("senkulpa",search) searchResults = wikia.search("senkulpa",search)
if len(searchResults) > 0: if len(searchResults) > 0:
foundPage = True
searchResult = searchResults[0].replace(",","%2C") searchResult = searchResults[0].replace(",","%2C")
self.bot.log("Found page \""+searchResult+"\"") self.bot.log("Found page \""+searchResult+"\"")
page = wikia.page("senkulpa",searchResult) page = wikia.page("senkulpa",searchResult)
@ -137,15 +150,39 @@ class Other():
images = page.images images = page.images
if len(images) > 0: if len(images) > 0:
image = images[len(images)-1]+"/revision/latest?path-prefix=da" image = images[len(images)-1]+"/revision/latest?path-prefix=da"
return page.title, content, image
else: else:
return page.title, content, "" image = ""
else: else:
self.bot.log("Couldn't find the page (error code 1002)") self.bot.log("Couldn't find the page")
return "", "Couldn't find page (error code 1002)", "" await ctx.send("Couldn't find page (error code 1002)")
def rollDice(self, user, rollString): if foundPage:
self.bot.log("Sending the embedded message",str(ctx.channel_id))
content += f"\n[Læs mere]({page.url})"
embed = discord.Embed(title = page.title, description = content, colour=0xDEADBF)
if image != "":
embed.set_thumbnail(url=image)
await ctx.send(embed = embed)
async def rollDice(self, ctx, rollString):
user = ctx.author.display_name
while len(rollString) > 1 and rollString[0] == " ": while len(rollString) > 1 and rollString[0] == " ":
rollString = rollString[1:] rollString = rollString[1:]
return user+" :game_die:\n"+str(d20.roll(rollString, allow_comments=True,stringifier=MyStringifier()))
roll = d20.roll(rollString, allow_comments=True, stringifier=MyStringifier())
await ctx.send(f"{user} :game_die:\n{roll}")
async def helpFunc(self, ctx, command):
if command == "":
with open("resources/help/help.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = "Help", description = text,colour = 0x59f442)
await ctx.send(embed = em)
else:
self.bot.log(f"Looking for help-{command}.txt",str(ctx.channel_id))
with open(f"resources/help/help-{command}.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = command.capitalize(), description = text,colour = 0x59f442)
await ctx.send(embed = em)

View File

@ -1,5 +1,6 @@
import json import json
import string import string
import discord
class StarWarsChar(): class StarWarsChar():
def __init__(self, bot): def __init__(self, bot):
@ -470,7 +471,10 @@ class StarWarsChar():
return cmd return cmd
def parseChar(self,user : str, cmd : str): async def parseChar(self, ctx, parameters : str):
user = f"#{ctx.author.id}"
cmd = string.capwords(parameters.replace("+","+ ").replace("-","- ").replace(",",", "))
returnEmbed = False
cmd = self.replaceSpaces(cmd) cmd = self.replaceSpaces(cmd)
@ -487,8 +491,9 @@ class StarWarsChar():
if cmd == "": if cmd == "":
if userCharacter != None: if userCharacter != None:
text1, text2 = self.characterSheet(userCharacter) title, text = self.characterSheet(userCharacter)
return text1, self.replaceWithSpaces(text2) text = self.replaceWithSpaces(text)
returnEmbed = True
else: else:
self.bot.log("Makin' a character for "+self.bot.databaseFuncs.getName(user)) self.bot.log("Makin' a character for "+self.bot.databaseFuncs.getName(user))
with open("resources/starWars/starwarstemplates.json", "r") as f: with open("resources/starWars/starwarstemplates.json", "r") as f:
@ -496,14 +501,20 @@ class StarWarsChar():
newChar = templates["Character"] newChar = templates["Character"]
newChar["_id"] = user newChar["_id"] = user
self.bot.database["starwars characters"].insert_one(newChar) self.bot.database["starwars characters"].insert_one(newChar)
return "", "Character for " + self.bot.databaseFuncs.getName(user) + " created" await ctx.send("Character for " + self.bot.databaseFuncs.getName(user) + " created")
else: else:
if cmd == "Purge": if cmd == "Purge":
self.bot.log("Deleting "+self.bot.databaseFuncs.getName(user)+"'s character") self.bot.log("Deleting "+self.bot.databaseFuncs.getName(user)+"'s character")
self.bot.database["starwars characters"].delete_one({"_id":user}) self.bot.database["starwars characters"].delete_one({"_id":user})
return "", "Character for " + self.bot.databaseFuncs.getName(user) + " deleted" await ctx.send("Character for " + self.bot.databaseFuncs.getName(user) + " deleted")
else: else:
return "", self.replaceWithSpaces(str(self.charData(user,cmd))) await ctx.send(self.replaceWithSpaces(str(self.charData(user,cmd))))
if returnEmbed:
em = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.send(embed = em)
def lightsaberChar(self,user : str): def lightsaberChar(self,user : str):
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user}) userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

View File

@ -4,13 +4,13 @@ class StarWarsDestiny():
def destinyNew(self, num : int): def destinyNew(self, num : int):
self.bot.log("Creating a new destiny pool with "+str(num)+" players") self.bot.log("Creating a new destiny pool with "+str(num)+" players")
roll, diceResults = self.bot.starwarsroll.roll(0,0,0,0,0,0,num) roll, diceResults = self.bot.starWars.roll.roll(0,0,0,0,0,0,num)
roll = "".join(sorted(roll)) roll = "".join(sorted(roll))
with open("resources/starWars/destinyPoints.txt","wt") as f: with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(roll) f.write(roll)
return "Rolled for Destiny Points and got:\n"+self.bot.starwarsroll.diceResultToEmoji(diceResults)+"\n"+self.bot.starwarsroll.resultToEmoji(roll) return "Rolled for Destiny Points and got:\n"+self.bot.starWars.roll.diceResultToEmoji(diceResults)+"\n"+self.bot.starWars.roll.resultToEmoji(roll)
def destinyUse(self, user : str): def destinyUse(self, user : str):
with open("resources/starWars/destinyPoints.txt","rt") as f: with open("resources/starWars/destinyPoints.txt","rt") as f:
@ -24,7 +24,7 @@ class StarWarsDestiny():
with open("resources/starWars/destinyPoints.txt","wt") as f: with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points) f.write(points)
self.bot.log("Did it") self.bot.log("Did it")
return "Used a dark side destiny point. Destiny pool is now:\n"+self.bot.starwarsroll.resultToEmoji(points) return "Used a dark side destiny point. Destiny pool is now:\n"+self.bot.starWars.roll.resultToEmoji(points)
else: else:
self.bot.log("There were no dark side destiny points") self.bot.log("There were no dark side destiny points")
return "No dark side destiny points" return "No dark side destiny points"
@ -36,31 +36,37 @@ class StarWarsDestiny():
with open("resources/starWars/destinyPoints.txt","wt") as f: with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points) f.write(points)
self.bot.log("Did it") self.bot.log("Did it")
return "Used a light side destiny point. Destiny pool is now:\n"+self.bot.starwarsroll.resultToEmoji(points) return "Used a light side destiny point. Destiny pool is now:\n"+self.bot.starWars.roll.resultToEmoji(points)
else: else:
self.bot.log("There were no dark side destiny points") self.bot.log("There were no dark side destiny points")
return "No light side destiny points" return "No light side destiny points"
def parseDestiny(self, user : str, cmd : str): async def parseDestiny(self, ctx, cmd : str):
user = f"#{ctx.author.id}"
if cmd != "": if cmd != "":
while cmd[0] == ' ': while cmd[0] == ' ':
cmd = cmd[1:] cmd = cmd[1:]
if cmd == "": if cmd == "":
break break
if cmd == "": if cmd == "":
self.bot.log("Retrieving destiny pool info") self.bot.log("Retrieving destiny pool info")
with open("resources/starWars/destinyPoints.txt","rt") as f: with open("resources/starWars/destinyPoints.txt","rt") as f:
return self.bot.starwarsroll.resultToEmoji(f.read()) sendMessage = self.bot.starWars.roll.resultToEmoji(f.read())
else: else:
commands = cmd.upper().split(" ") commands = cmd.upper().split(" ")
if commands[0] == "N": if commands[0] == "N":
if len(commands) > 1: if len(commands) > 1:
return self.destinyNew(int(commands[1])) sendMessage = self.destinyNew(int(commands[1]))
else: else:
return "You need to give an amount of players (error code 921)" sendMessage = "You need to give an amount of players (error code 921)"
elif commands[0] == "U": elif commands[0] == "U":
return self.destinyUse(user) sendMessage = self.destinyUse(user)
else: else:
return "I didn't quite understand that (error code 922)" sendMessage = "I didn't quite understand that (error code 922)"
messageList = sendMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
await ctx.channel.send(messageItem)

View File

@ -239,7 +239,7 @@ class StarWarsRoll():
return random.choice(table) return random.choice(table)
# Rolls for critical injury # Rolls for critical injury
def critRoll(self, addington : int): async def critRoll(self, ctx, addington : int):
dd = "<:difficulty:690973992470708296>" dd = "<:difficulty:690973992470708296>"
sd = "<:setback:690972157890658415>" sd = "<:setback:690972157890658415>"
bd = "<:boost:690972178216386561>" bd = "<:boost:690972178216386561>"
@ -253,14 +253,14 @@ class StarWarsRoll():
"**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+dd] * 5 + [ "**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+dd] * 5 + [
"**Stunned**: The target is staggered until the end of his next turn, "+dd] * 5 + [ "**Stunned**: The target is staggered until the end of his next turn, "+dd] * 5 + [
"**Stinger**: Increase the difficulty of next check by one, "+dd] * 5 + [ "**Stinger**: Increase the difficulty of next check by one, "+dd] * 5 + [
"**Bowled Over**: The target is knocked prone and suffers 1 sttrain, "+dd+dd] * 5 + [ "**Bowled Over**: The target is knocked prone and suffers 1 strain, "+dd+dd] * 5 + [
"**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+dd+dd] * 5 + [ "**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+dd+dd] * 5 + [ "**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+dd+dd] * 5 + [ "**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Slightly Dazed**: The target is disoriented until the end of the encounter, "+dd+dd] * 5 + [ "**Slightly Dazed**: The target is disoriented until the end of the encounter, "+dd+dd] * 5 + [
"**Scattered Senses**: The target removes all "+bd+" from skill checks until the end of the encounter, "+dd+dd] * 5 + [ "**Scattered Senses**: The target removes all "+bd+" from skill checks until the end of the encounter, "+dd+dd] * 5 + [
"**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+dd+dd] * 5 + [ "**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+dd+dd] * 5 + [
"**Overpowered**: The target leaves himselp open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+dd+dd] * 5 + [ "**Overpowered**: The target leaves himself open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+dd+dd] * 5 + [
"**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+dd+dd] * 5 + [ "**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+dd+dd] * 5 + [
"**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+dd+dd] * 5 + [ "**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**At the brink**: The target suffers 1 strain each time he performs an action, "+dd+dd+dd] * 5 + [ "**At the brink**: The target suffers 1 strain each time he performs an action, "+dd+dd+dd] * 5 + [
@ -288,56 +288,64 @@ class StarWarsRoll():
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"]) characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+dd+dd+dd+dd results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+dd+dd+dd+dd
return "Roll: "+str(roll)+"\nInjury:\n"+results sendMessage = "Roll: "+str(roll)+"\nInjury:\n"+results
messageList = sendMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
await ctx.channel.send(messageItem)
# Parses the command into something the other functions understand # Parses the command into something the other functions understand
def parseRoll(self, user : str,cmd : str = ""): async def parseRoll(self, ctx, cmd : str = ""):
user = f"#{ctx.author.id}"
cmd = re.sub(' +',' ',cmd.upper()) + " " cmd = re.sub(' +',' ',cmd.upper()) + " "
if cmd[0] == " ": if cmd[0] == " ":
cmd = cmd[1:] cmd = cmd[1:]
cmd = self.bot.starwarschar.replaceSpaces(string.capwords(cmd)) cmd = self.bot.starWars.character.replaceSpaces(string.capwords(cmd))
commands = cmd.split(" ") commands = cmd.split(" ")
validCommand = False
if commands[0] == "": if commands[0] == "":
rollParameters = [1,0,3,0,0,0,0] rollParameters = [1,0,3,0,0,0,0]
else: else:
rollParameters = [0,0,0,0,0,0,0] rollParameters = [0,0,0,0,0,0,0]
if string.capwords(commands[0]) == "Obligations": if string.capwords(commands[0]) == "Obligations":
try: sendMessage = self.obligationRoll()
return self.obligationRoll()
except:
self.bot.log("Obligation fucked up (error code 911)")
return "An error ocurred (error code 911)"
elif string.capwords(commands[0]) in skillData: elif string.capwords(commands[0]) in skillData:
self.bot.log("Oh look! This guy has skills!") self.bot.log("Oh look! This guy has skills!")
if self.bot.starwarschar.userHasChar: if self.bot.starWars.character.userHasChar(user):
self.bot.log("They have a character. That much we know") self.bot.log("They have a character. That much we know")
skillLevel = self.bot.starwarschar.charData(user,"Skills " + string.capwords(commands[0])) skillLevel = self.bot.starWars.character.charData(user,"Skills " + string.capwords(commands[0]))
if string.capwords(commands[0]) == "Lightsaber": if string.capwords(commands[0]) == "Lightsaber":
self.bot.log("The skill is lightsaber") self.bot.log("The skill is lightsaber")
charLevel = self.bot.starwarschar.charData(user,"Characteristics " + self.bot.starwarschar.lightsaberChar(user)) charLevel = self.bot.starWars.character.charData(user,"Characteristics " + self.bot.starWars.character.lightsaberChar(user))
else: else:
charLevel = self.bot.starwarschar.charData(user,"Characteristics " + skillData[string.capwords(commands[0])]) charLevel = self.bot.starWars.character.charData(user,"Characteristics " + skillData[string.capwords(commands[0])])
abilityDice = abs(charLevel-skillLevel) abilityDice = abs(charLevel-skillLevel)
proficiencyDice = min(skillLevel,charLevel) proficiencyDice = min(skillLevel,charLevel)
commands = [str(abilityDice)] + [str(proficiencyDice)] + commands[1:] commands = [str(abilityDice)] + [str(proficiencyDice)] + commands[1:]
self.bot.log("Converted skill to dice") self.bot.log("Converted skill to dice")
validCommand = True
else: else:
self.bot.log("Okay, no they don't i guess (error code 912)") self.bot.log("Okay, no they don't i guess")
return "You don't have a user. You can make one with /starwarscharacter (error code 912)" sendMessage = "You don't have a user. You can make one with /starwarscharacter"
elif string.capwords(commands[0]) in ["Ranged","Piloting"]: elif string.capwords(commands[0]) in ["Ranged","Piloting"]:
self.bot.log("They fucked up writing the name of a ranged or piloting skill") self.bot.log("They fucked up writing the name of a ranged or piloting skill")
if string.capwords(commands[0]) == "Ranged": if string.capwords(commands[0]) == "Ranged":
return "Did you mean \"Ranged - Heavy\" or \"Ranged - Light\" (error code 913)" sendMessage = "Did you mean \"Ranged - Heavy\" or \"Ranged - Light\" (error code 913)"
else: else:
return "Did you mean \"Piloting - Planetary\" or \"Piloting - Space\" (error code 913)" sendMessage = "Did you mean \"Piloting - Planetary\" or \"Piloting - Space\" (error code 913)"
else:
validCommand = True
try: if validCommand:
self.bot.log("Converting commands to dice") self.bot.log("Converting commands to dice")
for x, command in enumerate(commands): for x, command in enumerate(commands):
if command != "": if command != "":
@ -358,21 +366,26 @@ class StarWarsRoll():
rollParameters[6] = int(command.replace("F","")) rollParameters[6] = int(command.replace("F",""))
else: else:
rollParameters[x] = int(command) rollParameters[x] = int(command)
except:
self.bot.log("Someone fucked u-up! (it was them) (error code 914)")
return "Invalid input! (error code 914)"
self.bot.log("Rolling "+str(rollParameters)) self.bot.log("Rolling "+str(rollParameters))
rollResults, diceResults = self.roll(rollParameters[0],rollParameters[1],rollParameters[2],rollParameters[3],rollParameters[4],rollParameters[5],rollParameters[6]) rollResults, diceResults = self.roll(rollParameters[0],rollParameters[1],rollParameters[2],rollParameters[3],rollParameters[4],rollParameters[5],rollParameters[6])
simplified = self.simplify(rollResults) simplified = self.simplify(rollResults)
name = self.bot.starwarschar.getCharName(user) name = self.bot.starWars.character.getCharName(user)
self.bot.log("Returns results and simplified results") self.bot.log("Returns results and simplified results")
if simplified == "": if simplified == "":
return name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\nEverything cancels out!" sendMessage = name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\nEverything cancels out!"
else: else:
return name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\n" + self.resultToEmoji(simplified) sendMessage = name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\n" + self.resultToEmoji(simplified)
messageList = sendMessage.split("\n")
await ctx.send(messageList[0])
if len(messageList) > 1:
for messageItem in messageList[1:]:
if messageItem == "":
self.bot.log("Tried to send empty message")
else:
await ctx.channel.send(messageItem)

View File

@ -44,6 +44,7 @@ Comments, strings, variable names, class names, docstrings, as well as all other
## Code Style ## Code Style
All the Python code should follow the [PEP 8 guidelines](https://www.python.org/dev/peps/pep-0008/), with the following differences: All the Python code should follow the [PEP 8 guidelines](https://www.python.org/dev/peps/pep-0008/), with the following differences:
+ Variable and function names must be camelCase, and must fully consist of either full words or common/understandable abbreviations. + Variable and function names must be camelCase, and must fully consist of either full words or common/understandable abbreviations.
+ Use f-strings when applicable.
### Documentation ### Documentation
+ Comment lines should not exede 72 characters. + Comment lines should not exede 72 characters.
@ -84,7 +85,7 @@ All the Python code should follow the [PEP 8 guidelines](https://www.python.org/
Code called by a command should not have `try` and `except` statements. All errors should be raised to the `on_command_error()` or `Command.error()` functions, where they can be dealt with. Code called by a command should not have `try` and `except` statements. All errors should be raised to the `on_command_error()` or `Command.error()` functions, where they can be dealt with.
## Cogs ## Cogs
The `Command` methods in cogs should only exist to perform small tasks or call code from elsewhere in the Gwendolyn code. Therefore, a single `Command` method should not contain more than 3 lines of code and should not use any modules other than `Discord.py` and the Gwendolyn modules. The `Command` methods in cogs should only exist to perform small tasks or call code from elsewhere in the Gwendolyn code. Therefore, a single `Command` method should not contain more than 3 lines of code and should not use any modules other than `Discord.py` and the Gwendolyn modules. If a cog method calls a function in Gwendolyn, ctx must be passed, and the function should handle sending messages.
## Codebase Management ## Codebase Management
### Folders ### Folders
@ -102,11 +103,11 @@ Things you should know about the logging:
+ The function can take either a list of strings or a string as its first parameter. If the parameter is a string, it is converted to a list of 1 string. + The function can take either a list of strings or a string as its first parameter. If the parameter is a string, it is converted to a list of 1 string.
+ The first string in the list is printed. All strings in the list are logged to the log-file. + The first string in the list is printed. All strings in the list are logged to the log-file.
+ If the list is longer than 1 string, `(details in log)` is added to the printed string. + If the list is longer than 1 string, `(details in log)` is added to the printed string.
+ The level parameter is 20 by default, which means the level is `INFO`. 40 corresponds to a level of `ERROR`, and 10 corresponds to a level of `DEBUG`. Only use these levels when logging. + The level parameter is 20 by default, which means the level is `INFO`. 40 corresponds to a level of `ERROR`, and 25 corresponds to `print`.
+ Logs of level `DEBUG` are not printed. + Logs of level `INFO` are not printed.
+ Logs of level `ERROR` should only be created in the `on_command_error()` or `Command.error()` functions. + Logs of level `ERROR` should only be created in the `on_command_error()`, `on_error()` or `Command.error()` functions.
### Logging rules ### Logging rules
1. Never call the `logThis()` function from `/utils/utilFuncs/`. Always call `bot.log`. 1. Never call the `logThis()` function from `/utils/utilFuncs/`. Always call `bot.log`.
1. The `on_slash_command()` and `on_ready()` events are the only times log should be called at level 20.`DEBUG` level logs should be used for all other logging. 1. The `on_slash_command()` and `on_ready()` events are the only times log should be called at level 25. `INFO` level logs should be used for all other logging.
1. Always provide the channel id if available. Although you shouldn't pass the channel id to a function purely to use it in logs. 1. Always provide the channel id if available. Although you shouldn't pass the channel id to a function purely to use it in logs.

View File

@ -6,7 +6,8 @@ cachetools==4.2.1
certifi==2020.12.5 certifi==2020.12.5
chardet==3.0.4 chardet==3.0.4
d20==1.0.4 d20==1.0.4
discord.py==1.6.0 discord-py-slash-command @ git+https://github.com/eunwoo1104/discord-py-slash-command.git@3c63f9fe9d186c8492e85c3153aff268f1dd5cae
discord.py==1.7.1
dnspython==2.1.0 dnspython==2.1.0
finnhub-python==2.1.0 finnhub-python==2.1.0
gitdb==4.0.7 gitdb==4.0.7
@ -14,7 +15,9 @@ GitPython==3.1.0
greenlet==1.0.0 greenlet==1.0.0
idna==2.10 idna==2.10
IMDbPY==6.8 IMDbPY==6.8
inflect==5.3.0
jaraco.context==4.0.0 jaraco.context==4.0.0
jaraco.itertools==6.0.1
lark-parser==0.9.0 lark-parser==0.9.0
lxml==4.5.0 lxml==4.5.0
more-itertools==8.7.0 more-itertools==8.7.0
@ -24,9 +27,10 @@ numpy==1.18.2
Pillow==7.1.1 Pillow==7.1.1
pymongo==3.11.3 pymongo==3.11.3
requests==2.25.1 requests==2.25.1
six==1.15.0
smmap==4.0.0 smmap==4.0.0
soupsieve==2.2.1 soupsieve==2.2.1
SQLAlchemy==1.4.3 SQLAlchemy==1.4.5
typing-extensions==3.7.4.3 typing-extensions==3.7.4.3
urllib3==1.25.8 urllib3==1.25.8
websockets==8.1 websockets==8.1

View File

@ -1 +1 @@
Kommandoen `/blackjack` starter et spil blackjack. `/blackjack bet [beløb]` lader dig vædde en mængde af dine GwendoBucks. Du bruger `/blackjack hit`, `/blackjack stand`, `/blackjack split` og `/blackjack double` i løbet af spillet. Kommandoen `/blackjack start` starter et spil blackjack. `/blackjack bet [beløb]` lader dig vædde en mængde af dine GwendoBucks. Du bruger `/blackjack hit`, `/blackjack stand`, `/blackjack split` og `/blackjack double` i løbet af spillet.

View File

@ -40,6 +40,29 @@
} }
] ]
}, },
"blackjackCards" : {
"base" : "blackjack",
"name" : "cards",
"description" : "Get a count of the cards used in blackjack games"
},
"blackjackDouble" : {
"base" : "blackjack",
"name" : "double",
"description" : "Double your bet in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to double your bet on",
"type" : 4,
"required" : "false"
}
]
},
"blackjackHilo" : {
"base" : "blackjack",
"name" : "hilo",
"description" : "Get the current hi-lo value for the cards used in blackjack games"
},
"blackjackHit" : { "blackjackHit" : {
"base" : "blackjack", "base" : "blackjack",
"name" : "hit", "name" : "hit",
@ -53,6 +76,24 @@
} }
] ]
}, },
"blackjackShuffle" : {
"base" : "blackjack",
"name" : "shuffle",
"description" : "Shuffle the cards used in blackjack games"
},
"blackjackSplit" : {
"base" : "blackjack",
"name" : "split",
"description" : "Split your hand in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to split, in case you've already split once",
"type" : 4,
"required" : "false"
}
]
},
"blackjackStand" : { "blackjackStand" : {
"base" : "blackjack", "base" : "blackjack",
"name" : "stand", "name" : "stand",
@ -99,23 +140,10 @@
} }
] ]
}, },
"connectFourStop" : { "connectFourSurrender" : {
"base" : "connectFour", "base" : "connectFour",
"name" : "stop", "name" : "surrender",
"description" : "Stop the game of connect four" "description" : "Surrender the game of connect four"
},
"connectFourPlace" : {
"base" : "connectFour",
"name" : "place",
"description" : "Place a piece",
"options" : [
{
"name" : "column",
"description" : "The column to place the piece",
"type" : 4,
"required" : "true"
}
]
}, },
"downloading" : { "downloading" : {
"name" : "downloading", "name" : "downloading",

View File

@ -1,6 +1,7 @@
"""A collections of utilities used by Gwendolyn and her functions""" """A collections of utilities used by Gwendolyn and her functions"""
__all__ = ["Options", "Credentials", "databaseFuncs", "getParams", "logThis", "cap", "makeFiles", "replaceMultiple", "emojiToCommand"] __all__ = ["Options", "Credentials", "databaseFuncs", "EventHandler", "ErrorHandler", "getParams", "logThis", "cap", "makeFiles", "replaceMultiple", "emojiToCommand"]
from .helperClasses import Options, Credentials, databaseFuncs from .helperClasses import Options, Credentials, databaseFuncs
from .eventHandlers import EventHandler, ErrorHandler
from .utilFunctions import getParams, logThis, cap, makeFiles, replaceMultiple, emojiToCommand from .utilFunctions import getParams, logThis, cap, makeFiles, replaceMultiple, emojiToCommand

103
utils/eventHandlers.py Normal file
View File

@ -0,0 +1,103 @@
import discord, traceback, discord_slash, sys
from discord.ext import commands
from .utilFunctions import emojiToCommand
class EventHandler():
def __init__(self, bot):
self.bot = bot
async def on_slash_command(self, ctx):
if ctx.subcommand_name is not None:
subcommand = f" {ctx.subcommand_name} "
else:
subcommand = " "
args = " ".join([str(i) for i in ctx.args])
fullCommand = f"/{ctx.command}{subcommand}{args}"
logMessage = f"{ctx.author.display_name} ran {fullCommand}"
self.bot.log(logMessage, str(ctx.channel_id), level = 25)
async def on_ready(self):
await self.bot.databaseFuncs.syncCommands()
self.bot.log("Logged in as "+self.bot.user.name+", "+str(self.bot.user.id), level = 25)
game = discord.Game("Use /help for commands")
await self.bot.change_presence(activity=game, status = discord.Status.online)
async def on_reaction_add(self, reaction, user):
if user.bot == False:
message = reaction.message
channel = message.channel
self.bot.log(f"{user.display_name} reacted to a message",str(channel.id))
try:
connectFourTheirTurn, piece = self.bot.databaseFuncs.connectFourReactionTest(channel,message,"#"+str(user.id))
except:
connectFourTheirTurn = False
bedreNetflixMessage, addMovie, imdbIds = self.bot.databaseFuncs.bedreNetflixReactionTest(channel, message)
if connectFourTheirTurn:
column = emojiToCommand(reaction.emoji)
await self.bot.games.connectFour.placePiece(message, f"#{user.id}", column-1)
elif bedreNetflixMessage and addMovie:
moviePick = emojiToCommand(reaction.emoji)
await message.delete()
if moviePick == "none":
imdbID = None
else:
imdbID = imdbIds[moviePick-1]
await self.bot.other.bedreNetflix.addMovie(channel,imdbID)
elif bedreNetflixMessage and not addMovie:
showPick = emojiToCommand(reaction.emoji)
await message.delete()
if showPick == "none":
imdbName = None
else:
imdbName = imdbIds[showPick-1]
await self.bot.other.bedreNetflix.addShow(channel,imdbName)
elif self.bot.databaseFuncs.hangmanReactionTest(channel, message, f"#{user.id}"):
self.bot.log("They reacted to the hangman message")
if ord(reaction.emoji) in range(127462,127488):
guess = chr(ord(reaction.emoji)-127397)
await self.bot.games.hangman.guess(message, f"#{user.id}", guess)
else:
self.bot.log("Bot they didn't react with a valid guess")
class ErrorHandler():
def __init__(self, bot):
self.bot = bot
async def on_slash_command_error(self, ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.send("That's not a command (error code 001)")
elif isinstance(error, discord.errors.NotFound):
self.bot.log("Deleted message before I could add all reactions")
elif isinstance(error, commands.errors.MissingRequiredArgument):
self.bot.log(f"{error}",str(ctx.channel_id))
await ctx.send("Missing command parameters (error code 002). Try using `!help [command]` to find out how to use the command.")
else:
exception = traceback.format_exception(type(error), error, error.__traceback__)
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{ctx.name}", f"{exceptionString}"],str(ctx.channel_id), 40)
if isinstance(error, discord.errors.NotFound):
self.bot.log("Context is non-existant", level = 40)
else:
await ctx.send("Something went wrong (error code 000)")
async def on_error(self, method):
errorType = sys.exc_info()[0]
if errorType == discord.errors.NotFound:
self.bot.log("Deleted message before I could add all reactions")
else:
exception = traceback.format_exc()
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in {method}", f"{exceptionString}"], level = 40)

View File

@ -53,12 +53,12 @@ class databaseFuncs():
def getName(self, userID): def getName(self, userID):
user = self.bot.database["users"].find_one({"_id":userID}) user = self.bot.database["users"].find_one({"_id":userID})
if user != None: if userID == f"#{self.bot.user.id}":
return "Gwendolyn"
elif user != None:
return user["user name"] return user["user name"]
elif userID == "Gwendolyn":
return userID
else: else:
self.bot.log("Couldn't find user "+userID) self.bot.log(f"Couldn't find user {userID}")
return userID return userID
def getID(self,userName): def getID(self,userName):
@ -70,7 +70,7 @@ class databaseFuncs():
self.bot.log("Couldn't find user "+userName) self.bot.log("Couldn't find user "+userName)
return None return None
def deleteGame(self, gameType,channel): def deleteGame(self, gameType, channel):
self.bot.database[gameType].delete_one({"_id":channel}) self.bot.database[gameType].delete_one({"_id":channel})
def stopServer(self): def stopServer(self):
@ -78,6 +78,7 @@ class databaseFuncs():
self.bot.database["blackjack games"].delete_many({}) self.bot.database["blackjack games"].delete_many({})
self.bot.database["connect 4 games"].delete_many({}) self.bot.database["connect 4 games"].delete_many({})
self.bot.database["hangman games"].delete_many({}) self.bot.database["hangman games"].delete_many({})
self.bot.database["hex games"].delete_many({})
if not self.bot.options.testing: if not self.bot.options.testing:
g = git.cmd.Git("") g = git.cmd.Git("")
@ -100,7 +101,7 @@ class databaseFuncs():
else: else:
return False, 0 return False, 0
def hangmanReactionTest(self, channel,message): def hangmanReactionTest(self, channel, message, user):
try: try:
with open("resources/games/oldImages/hangman"+str(channel.id), "r") as f: with open("resources/games/oldImages/hangman"+str(channel.id), "r") as f:
oldMessages = f.read().splitlines() oldMessages = f.read().splitlines()
@ -111,8 +112,11 @@ class databaseFuncs():
for oldMessage in oldMessages: for oldMessage in oldMessages:
oldMessageID = int(oldMessage) oldMessageID = int(oldMessage)
if message.id == oldMessageID: if message.id == oldMessageID:
self.bot.log("They reacted to the hangman game") game = self.bot.database["hangman games"].find_one({"_id":str(channel.id)})
gameMessage = True if user == game["player"]:
gameMessage = True
break
return gameMessage return gameMessage

View File

@ -1,11 +1,21 @@
import json import json
import time
import logging import logging
import os import os
import sys
from .helperClasses import Options from .helperClasses import Options
FORMAT = " %(asctime)s | %(name)-16s | %(levelname)-8s | %(message)s"
PRINTFORMAT = "%(asctime)s - %(message)s"
DATEFORMAT = "%Y-%m-%d %H:%M:%S"
logging.addLevelName(25, "PRINT") logging.addLevelName(25, "PRINT")
logging.basicConfig(filename="gwendolyn.log", level=logging.INFO) logging.basicConfig(format=FORMAT, datefmt=DATEFORMAT, level=logging.INFO, filename="gwendolyn.log")
logger = logging.getLogger("Gwendolyn")
printer = logging.getLogger("printer")
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(fmt = PRINTFORMAT, datefmt=DATEFORMAT))
printer.addHandler(handler)
printer.propagate = False
def getParams(): def getParams():
with open("resources/slashParameters.json", "r") as f: with open("resources/slashParameters.json", "r") as f:
@ -20,25 +30,24 @@ def getParams():
return params return params
def logThis(messages, channel : str = "", level : int = 20): def logThis(messages, channel : str = "", level : int = 20):
localtime = time.asctime(time.localtime(time.time()))
channel = channel.replace("Direct Message with ","") channel = channel.replace("Direct Message with ","")
if type(messages) is str: if type(messages) is str:
messages = [messages] messages = [messages]
printMessage = messages[0]
for x, msg in enumerate(messages): for x, msg in enumerate(messages):
if channel == "": if channel != "":
messages[x] = localtime+" - "+msg messages[x] = f"{msg} - ({channel})"
else:
messages[x] = localtime+" ("+channel+") - "+msg
if len(messages) > 1: if len(messages) > 1:
messages[0] += " (details in log)" printMessage += " (details in log)"
if level >= 25: if level >= 25:
print(messages[0]) printer.log(level, printMessage)
for logMessage in messages: for logMessage in messages:
logging.log(level, logMessage) logger.log(level, logMessage)
# Capitalizes all words except some of them # Capitalizes all words except some of them
def cap(s): def cap(s):