import asyncio import discord import html import json import random import time from random import shuffle from redbot.core import commands from redbot.core.data_manager import bundled_data_path class CardsAgainstHumanity(commands.Cog): """Play Cards Against Humanity in DMs.""" async def red_delete_data_for_user(self, **kwargs): """ Nothing to delete """ return def __init__(self, bot): self.bot = bot self.games = [] self.maxBots = 5 # Max number of bots that can be added to a game - don't count toward max players self.maxPlayers = 10 # Max players for ranjom joins self.maxDeadTime = 3600 # Allow an hour of dead time before killing a game self.checkTime = 300 # 5 minutes between dead time checks self.winAfter = 10 # 10 wins for the game self.botWaitMin = 5 # Minimum number of seconds before the bot makes a decision (default 5) self.botWaitMax = 30 # Max number of seconds before a bot makes a decision (default 30) self.userTimeout = 500 # 5 minutes to timeout self.utCheck = 30 # Check timeout every 30 seconds self.utWarn = 60 # Warn the user if they have 60 seconds or less before being kicked self.charset = "1234567890" self.botName = "Rando Cardrissian" self.minMembers = 3 self.bot.loop.create_task(self.checkDead()) self.bot.loop.create_task(self.checkUserTimeout()) def cleanJson(self, json): json = html.unescape(json) # Clean out html formatting json = json.replace("_", "[blank]") json = json.replace("
", "\n") json = json.replace("
", "\n") json = json.replace("", "*") json = json.replace("", "*") return json def displayname(self, member: discord.Member): # A helper function to return the member's display name nick = name = None try: nick = member.nick except AttributeError: pass try: name = member.name except AttributeError: pass if nick: return nick if name: return name return None def memberforname(self, name, server): # Check nick first - then name for member in server.members: if member.nick: if member.nick.lower() == name.lower(): return member for member in server.members: if member.name.lower() == name.lower(): return member # No member yet - try ID memID = "".join(list(filter(str.isdigit, name))) newMem = self.memberforid(memID, server) if newMem: return newMem return None @staticmethod def memberforid(checkid, server): for member in server.members: if str(member.id) == str(checkid): return member return None def getreadabletimebetween(self, first, last): # A helper function to make a readable string between two times timeBetween = int(last - first) weeks = int(timeBetween / 604800) days = int((timeBetween - (weeks * 604800)) / 86400) hours = int((timeBetween - (days * 86400 + weeks * 604800)) / 3600) minutes = int((timeBetween - (hours * 3600 + days * 86400 + weeks * 604800)) / 60) seconds = int(timeBetween - (minutes * 60 + hours * 3600 + days * 86400 + weeks * 604800)) msg = "" if weeks > 0: if weeks == 1: msg = f"{msg}{str(weeks)} week, " else: msg = f"{msg}{str(weeks)} weeks, " if days > 0: if days == 1: msg = f"{msg}{str(days)} day, " else: msg = f"{msg}{str(days)} days, " if hours > 0: if hours == 1: msg = f"{msg}{str(hours)} hour, " else: msg = f"{msg}{str(hours)} hours, " if minutes > 0: if minutes == 1: msg = f"{msg}{str(minutes)} minute, " else: msg = f"{msg}{str(minutes)} minutes, " if seconds > 0: if seconds == 1: msg = f"{msg}{str(seconds)} second, " else: msg = f"{msg}{str(seconds)} seconds, " if not msg: return "0 seconds" else: return msg[:-2] async def checkUserTimeout(self): while True: # Wait first - then check await asyncio.sleep(self.utCheck) for game in self.games: if not game["Timeout"]: continue if len(game["Members"]) >= self.minMembers: # Game is started for member in game["Members"]: if member["IsBot"]: continue if game["Judging"]: if not member == game["Members"][game["Judge"]]: # Not the judge - don't hold against the user member["Time"] = int(time.time()) continue else: # Not judging if member == game["Members"][game["Judge"]]: # The judge - don't hold that against them member["Time"] = int(time.time()) continue currentTime = int(time.time()) userTime = member["Time"] downTime = currentTime - userTime # Check if downTime results in a kick if downTime >= self.userTimeout: # You gettin kicked, son. await self.removeMember(member["User"]) self.checkGame(game) continue # Check if downTime is in warning time if downTime >= (self.userTimeout - self.utWarn): # Check if we're at warning phase if self.userTimeout - downTime >= (self.utWarn - self.utCheck): kickTime = self.userTimeout - downTime if kickTime % self.utCheck: # Kick time isn't exact time - round out to the next loop kickTime = kickTime - (kickTime % self.utCheck) + self.utCheck # Warning time! timeString = self.getreadabletimebetween(0, kickTime) await self.sendToUser( member["User"], f"**WARNING** - You will be kicked from the game if you do not make a move in *{timeString}!*", ) else: for member in game["Members"]: # Reset timer member["Time"] = int(time.time()) async def checkDead(self): while True: # Wait first - then check await asyncio.sleep(self.checkTime) for game in self.games: gameTime = game["Time"] currentTime = int(time.time()) timeRemain = currentTime - gameTime if timeRemain > self.maxDeadTime: # Game is dead - quit it and alert members for member in game["Members"]: if member["IsBot"]: # Clear pending tasks and set to None if not member["Task"] == None: task = member["Task"] if not task.done(): task.cancel() member["Task"] = None continue await self.sendToUser( member["User"], f"Game id: *{game['ID']}* has been closed due to inactivity.", ) # Set running to false game["Running"] = False self.games.remove(game) async def checkPM(self, message): # Checks if we're talking in PM, and if not - outputs an error if isinstance(message.channel, discord.abc.PrivateChannel): # PM return True else: # Not in PM await message.channel.send("Cards Against Humanity commands must be run in Direct Messages with the bot.") return False def randomID(self, length=8): # Create a random id that doesn't already exist while True: # Repeat until found newID = "".join(random.choice(self.charset) for i in range(length)) exists = False for game in self.games: if game["ID"] == newID: exists = True break if not exists: break return newID def randomBotID(self, game, length=4): # Returns a random id for a bot that doesn't already exist while True: # Repeat until found newID = "".join(random.choice(self.charset) for i in range(length)) exists = False for member in game["Members"]: if member["ID"] == newID: exists = True break if not exists: break return newID async def userGame(self, user): # Returns the game the user is currently in if not len(str(user)) == 4: if not type(user) is int: # Assume it's a discord.Member/User user = user.id for game in self.games: for member in game["Members"]: if member["ID"] == user: # Found our user return game return None def gameForID(self, id): # Returns the game with the passed id for game in self.games: if game["ID"] == id: return game return None async def removeMember(self, user, game=None): if not len(str(user)) == 4: if not type(user) is int: # Assume it's a discord.Member/User user = user.id outcome = False removed = None if not game: game = await self.userGame(user) if game: for member in game["Members"]: if member["ID"] == user: removed = member outcome = True judgeChanged = False # Reset judging flag to retrigger actions game["Judging"] = False # Get current Judge - only if game has started if len(game["Members"]) >= self.minMembers: judge = game["Members"][game["Judge"]] game["Members"].remove(member) # Check if we're removing the current judge if judge == member: # Judge will change judgeChanged = True # Find out if our member was the last in line if game["Judge"] >= len(game["Members"]): game["Judge"] = 0 # Reset judge var judge = game["Members"][game["Judge"]] else: # Judge didn't change - so let's reset judge index index = game["Members"].index(judge) game["Judge"] = index else: judge = None # Just remove the member game["Members"].remove(member) if member["Creator"]: # We're losing the game creator - pick a new one for newCreator in game["Members"]: if not newCreator["IsBot"]: newCreator["Creator"] = True await self.sendToUser( newCreator["User"], "The creator of this game left. **YOU** are now the creator.", ) break # Remove submissions for sub in game["Submitted"]: # Remove deleted member and new judge's submissions if sub["By"] == member or sub["By"] == judge: # Found it! game["Submitted"].remove(sub) break if member["IsBot"]: if not member["Task"] == None: task = member["Task"] if not task.done(): task.cancel() member["Task"] = None else: await self.sendToUser( member["User"], f"**You were removed from game id:** ***{game['ID']}.***", ) # Removed, no need to finish the loop break if not outcome: return outcome # We removed someone - let's tell the world for member in game["Members"]: if member["IsBot"]: continue if removed["IsBot"]: msg = f"***{self.botName} ({removed['ID']})*** **left the game - reorganizing...**" else: msg = f"***{self.displayname(removed['User'])}*** **left the game - reorganizing...**" # Check if the judge changed if judgeChanged: # Judge changed newJudge = game["Members"][game["Judge"]] if newJudge["IsBot"]: msg += f"\n\n***{self.botName} ({newJudge['ID']})*** **is now judging!**" # Schedule judging task else: if newJudge == member: msg += "\n\n***YOU*** **are now judging!**" else: msg += f"\n\n***{newJudge['User']}*** **is now judging!**" await self.sendToUser(member["User"], msg) return game def checkGame(self, game): for member in game["Members"]: if not member["IsBot"]: return True # If we got here - only bots, or empty game # Kill all bots' loops for member in game["Members"]: if member["IsBot"]: # Clear pending tasks and set to None if not member["Task"] == None: task = member["Task"] if not task.done(): task.cancel() member["Task"] = None # Set running to false game["Running"] = False self.games.remove(game) return False async def typing(self, game, typeTime=5): # Allows us to show the bot typing waitTime = random.randint(self.botWaitMin, self.botWaitMax) preType = waitTime - typeTime if preType > 0: await asyncio.sleep(preType) for member in game["Members"]: if member["IsBot"]: continue await asyncio.sleep(0.1) await asyncio.sleep(typeTime) else: for member in game["Members"]: if member["IsBot"]: continue await asyncio.sleep(0.1) await asyncio.sleep(waitTime) async def botPick(self, ctx, bot, game): # Has the bot pick their card blackNum = game["BlackCard"]["Pick"] if blackNum == 1: cardSpeak = "card" else: cardSpeak = "cards" i = 0 cards = [] while i < blackNum: randCard = random.randint(0, len(bot["Hand"]) - 1) cards.append(bot["Hand"].pop(randCard)["Text"]) i += 1 await self.typing(game) # Make sure we haven't laid any cards if bot["Laid"] == False and game["Judging"] == False: newSubmission = {"By": bot, "Cards": cards} game["Submitted"].append(newSubmission) # Shuffle cards shuffle(game["Submitted"]) bot["Laid"] = True game["Time"] = currentTime = int(time.time()) await self.checkSubmissions(ctx, game, bot) async def botPickWin(self, ctx, game): totalUsers = len(game["Members"]) - 1 submitted = len(game["Submitted"]) if submitted >= totalUsers: # Judge is a bot - and all cards are in! await self.typing(game) # Pick a winner winner = random.randint(0, totalUsers - 1) await self.winningCard(ctx, game, winner) async def checkSubmissions(self, ctx, game, user=None): totalUsers = len(game["Members"]) - 1 submitted = len(game["Submitted"]) for member in game["Members"]: msg = "" # Is the game running? if len(game["Members"]) < self.minMembers: if member["IsBot"]: # Clear pending tasks and set to None if not member["Task"] == None: task = member["Task"] if not task.done(): # Task isn't finished - we're on a new hand, cancel it task.cancel() member["Task"] = None continue # not enough members - send the embed stat_embed = discord.Embed(color=discord.Color.red()) stat_embed.set_author( name=f"Not enough players to continue! ({len(game['Members'])}/{self.minMembers})" ) prefix = await self.bot.get_valid_prefixes() stat_embed.set_footer(text=f"Have other users join with: {prefix[0]}joincah {game['ID']}") await self.sendToUser(member["User"], stat_embed, True) continue if member["IsBot"] == True: continue # Check if we have a user if user: blackNum = game["BlackCard"]["Pick"] if blackNum == 1: card = "card" else: card = "cards" if user["IsBot"]: msg = f"*{self.botName} ({user['ID']})* submitted their {card}! " else: if not member == user: # Don't say this to the submitting user msg = f"*{self.displayname(user['User'])}* submitted their {card}! " if submitted < totalUsers: msg += f"{submitted}/{totalUsers} cards submitted..." if len(msg): # We have something to say await self.sendToUser(member["User"], msg) async def checkCards(self, ctx, game): while True: if not game["Running"]: break # wait for 1 second await asyncio.sleep(1) # Check for all cards if len(game["Members"]) < self.minMembers: # Not enough members continue # Enough members - let's check if we're judging if game["Judging"]: continue # Enough members, and not judging - let's check cards totalUsers = len(game["Members"]) - 1 submitted = len(game["Submitted"]) if submitted >= totalUsers: game["Judging"] = True # We have enough cards for member in game["Members"]: if member["IsBot"]: continue msg = "All cards have been submitted!" # if await self.sendToUser(member["User"], msg) await self.showOptions(ctx, member["User"]) # Check if a bot is the judge judge = game["Members"][game["Judge"]] if not judge["IsBot"]: continue # task = self.bot.loop.create_task(self.botPickWin(ctx, game)) task = asyncio.ensure_future(self.botPickWin(ctx, game)) judge["Task"] = task async def winningCard(self, ctx, game, card): # Let's pick our card and alert everyone winner = game["Submitted"][card] if winner["By"]["IsBot"]: winnerName = f"{self.botName} ({winner['By']['ID']})" winner["By"]["Points"] += 1 winner["By"]["Won"].append(game["BlackCard"]["Text"]) else: winnerName = self.displayname(winner["By"]["User"]) for member in game["Members"]: if member["IsBot"]: continue stat_embed = discord.Embed(color=discord.Color.gold()) stat_embed.set_footer(text=f"Cards Against Humanity - id: {game['ID']}") index = game["Members"].index(member) if index == game["Judge"]: stat_embed.set_author(name=f"You picked {winnerName}'s card!") elif member == winner["By"]: stat_embed.set_author(name="YOU WON!!") member["Points"] += 1 member["Won"].append(game["BlackCard"]["Text"]) else: stat_embed.set_author(name=f"{winnerName} won!") if len(winner["Cards"]) == 1: msg = "The **Winning** card was:\n\n{}".format("{}".format(" - ".join(winner["Cards"]))) else: msg = "The **Winning** cards were:\n\n{}".format("{}".format(" - ".join(winner["Cards"]))) await self.sendToUser(member["User"], stat_embed, True) await self.sendToUser(member["User"], msg) await asyncio.sleep(0.1) # await self.nextPlay(ctx, game) # Start the game loop event = game["NextHand"] self.bot.loop.call_soon_threadsafe(event.set) game["Time"] = currentTime = int(time.time()) async def gameCheckLoop(self, ctx, game): task = game["NextHand"] while True: if not game["Running"]: break # Clear the pending task task.clear() # Queue up the next hand await self.nextPlay(ctx, game) # Wait until our next clear await task.wait() async def messagePlayers(self, ctx, message, game, judge=False): # Messages all the users on in a game for member in game["Members"]: if member["IsBot"]: continue # Not bots if member is game["Members"][game["Judge"]]: # Is the judge if judge: await self.sendToUser(member["User"], message) else: # Not the judge await self.sendToUser(member["User"], message) async def sendToUser(self, user, message, embed_bool=False): try: if embed_bool: await user.send(embed=message) else: await user.send(message) except discord.errors.Forbidden: pass ################################################ async def showPlay(self, ctx, user): # Creates an embed and displays the current game stats stat_embed = discord.Embed(color=discord.Color.blue()) game = await self.userGame(user) if not game: return # Get the judge's name if game["Members"][game["Judge"]]["User"] == user: judge = "**YOU** are" else: if game["Members"][game["Judge"]]["IsBot"]: # Bot judge = f"*{self.botName} ({game['Members'][game['Judge']]['ID']})* is" else: judge = f"*{self.displayname(game['Members'][game['Judge']]['User'])}* is" # Get the Black Card try: blackCard = game["BlackCard"]["Text"] blackNum = game["BlackCard"]["Pick"] except Exception: blackCard = "None." blackNum = 0 msg = f"{judge} the judge.\n\n" msg += f"__Black Card:__\n\n**{blackCard}**\n\n" totalUsers = len(game["Members"]) - 1 submitted = len(game["Submitted"]) if len(game["Members"]) >= self.minMembers: if submitted < totalUsers: msg += f"{submitted}/{totalUsers} cards submitted..." else: msg += "All cards have been submitted!" await self.showOptions(ctx, user) return if not judge == "**YOU** are": # Judge doesn't need to lay a card prefix = await self.bot.get_valid_prefixes() if blackNum == 1: # Singular msg += f"\n\nLay a card with `{prefix[0]}lay [card number]`" elif blackNum > 1: # Plural msg += f"\n\nLay **{blackNum} cards** with `{prefix[0]}lay [card numbers separated by commas (1,2,3)]`" stat_embed.set_author(name="Current Play") stat_embed.set_footer(text=f"Cards Against Humanity - id: {game['ID']}") await self.sendToUser(user, stat_embed, True) await self.sendToUser(user, msg) async def showHand(self, ctx, user): # Shows the user's hand in an embed stat_embed = discord.Embed(color=discord.Color.green()) game = await self.userGame(user) if not game: return i = 0 msg = "" points = "? points" for member in game["Members"]: if member["ID"] == user.id: # Got our user if member["Points"] == 1: points = "1 point" else: points = f"{member['Points']} points" for card in member["Hand"]: i += 1 msg += f"{i}. {card['Text']}\n" try: blackCard = f"**{game['BlackCard']['Text']}**" except Exception: blackCard = "**None.**" stat_embed.set_author(name=f"Your Hand - {points}") stat_embed.set_footer(text=f"Cards Against Humanity - id: {game['ID']}") await self.sendToUser(user, stat_embed, True) await self.sendToUser(user, msg) async def showOptions(self, ctx, user): # Shows the judgement options stat_embed = discord.Embed(color=discord.Color.orange()) game = await self.userGame(user) if not game: return # Add title stat_embed.set_author(name="JUDGEMENT TIME!!") stat_embed.set_footer(text=f"Cards Against Humanity - id: {game['ID']}") await self.sendToUser(user, stat_embed, True) if game["Members"][game["Judge"]]["User"] == user: judge = "**YOU** are" else: if game["Members"][game["Judge"]]["IsBot"]: # Bot judge = f"*{self.botName} ({game['Members'][game['Judge']]['ID']})* is" else: judge = f"*{self.displayname(game['Members'][game['Judge']]['User'])}* is" blackCard = game["BlackCard"]["Text"] msg = f"{judge} judging.\n\n" msg += f"__Black Card:__\n\n**{blackCard}**\n\n" msg += "__Submitted White Cards:__\n\n" i = 0 for sub in game["Submitted"]: i += 1 msg += "{}. {}\n".format(i, " - ".join(sub["Cards"])) if judge == "**YOU** are": prefix = await self.bot.get_valid_prefixes() msg += f"\nPick a winner with `{prefix[0]}pick [submission number]`." await self.sendToUser(user, msg) async def drawCard(self, game): with open(str(bundled_data_path(self)) + "/deck.json", "r") as deck_file: deck = json.load(deck_file) # Draws a random unused card and shuffles the deck if needed totalDiscard = len(game["Discard"]) for member in game["Members"]: totalDiscard += len(member["Hand"]) if totalDiscard >= len(deck["whiteCards"]): # Tell everyone the cards were shuffled for member in game["Members"]: if member["IsBot"]: continue user = member["User"] await self.sendToUser(user, "Shuffling white cards...") # Shuffle the cards self.shuffle(game) while True: # Random grab a unique card index = random.randint(0, len(deck["whiteCards"]) - 1) if not index in game["Discard"]: game["Discard"].append(index) text = deck["whiteCards"][index] text = self.cleanJson(text) card = {"Index": index, "Text": text} return card def shuffle(self, game): # Adds discards back into the deck game["Discard"] = [] for member in game["Members"]: for card in member["Hand"]: game["Discard"].append(card["Index"]) async def drawCards(self, user, cards=10): if not len(str(user)) == 4: if not type(user) is int: # Assume it's a discord.Member/User user = user.id # fills the user's hand up to number of cards game = await self.userGame(user) for member in game["Members"]: if member["ID"] == user: # Found our user - let's draw cards i = len(member["Hand"]) while i < cards: # Draw unique cards until we fill our hand newCard = await self.drawCard(game) member["Hand"].append(newCard) i += 1 async def drawBCard(self, game): with open(str(bundled_data_path(self)) + "/deck.json", "r") as deck_file: deck = json.load(deck_file) # Draws a random black card totalDiscard = len(game["BDiscard"]) if totalDiscard >= len(deck["blackCards"]): # Tell everyone the cards were shuffled for member in game["Members"]: if member["IsBot"]: continue user = member["User"] await self.sendToUser(user, "Shuffling black cards...") # Shuffle the cards game["BDiscard"] = [] while True: # Random grab a unique card index = random.randint(0, len(deck["blackCards"]) - 1) if not index in game["BDiscard"]: game["BDiscard"].append(index) text = deck["blackCards"][index]["text"] text = self.cleanJson(text) game["BlackCard"] = {"Text": text, "Pick": deck["blackCards"][index]["pick"]} return game["BlackCard"] async def nextPlay(self, ctx, game): # Advances the game if len(game["Members"]) < self.minMembers: stat_embed = discord.Embed(color=discord.Color.red()) stat_embed.set_author(name=f"Not enough players to continue! ({len(game['Members'])}/{self.minMembers})") prefix = await self.bot.get_valid_prefixes() stat_embed.set_footer(text=f"Have other users join with: {prefix[0]}joincah {game['ID']}") for member in game["Members"]: if member["IsBot"]: continue await self.sendToUser(member["User"], stat_embed, True) return # Find if we have a winner winner = False stat_embed = discord.Embed(color=discord.Color.lighter_grey()) for member in game["Members"]: if member["IsBot"]: # Clear pending tasks and set to None if not member["Task"] == None: task = member["Task"] if not task.done(): # Task isn't finished - we're on a new hand, cancel it task.cancel() member["Task"] = None if member["Points"] >= self.winAfter: # We have a winner! winner = True if member["IsBot"]: stat_embed.set_author(name=f"{self.botName} ({member['ID']}) is the WINNER!!") else: stat_embed.set_author(name=f"{self.displayname(member['User'])} is the WINNER!!") stat_embed.set_footer(text="Congratulations!") break if winner: for member in game["Members"]: if not member["IsBot"]: await self.sendToUser(member["User"], stat_embed, True) # Reset all users member["Hand"] = [] member["Points"] = 0 member["Won"] = [] member["Laid"] = False member["Refreshed"] = False return game["Judging"] = False # Clear submitted cards game["Submitted"] = [] # We have enough members if game["Judge"] == -1: # First game - randomize judge game["Judge"] = random.randint(0, len(game["Members"]) - 1) else: game["Judge"] += 1 # Reset the judge if out of bounds if game["Judge"] >= len(game["Members"]): game["Judge"] = 0 # Draw the next black card bCard = await self.drawBCard(game) # Draw cards for member in game["Members"]: member["Laid"] = False await self.drawCards(member["ID"]) # Show hands for member in game["Members"]: if member["IsBot"]: continue await self.showPlay(ctx, member["User"]) index = game["Members"].index(member) if not index == game["Judge"]: await self.showHand(ctx, member["User"]) await asyncio.sleep(0.1) # Have the bots lay their cards for member in game["Members"]: if not member["IsBot"]: continue if member["ID"] == game["Members"][game["Judge"]]["ID"]: continue # Not a human player, and not the judge # task = self.bot.loop.create_task(self.botPick(ctx, member, game))\ task = asyncio.ensure_future(self.botPick(ctx, member, game)) member["Task"] = task # await self.botPick(ctx, member, game) @commands.command() async def game(self, ctx, *, message=None): """Displays the game's current status.""" if not await self.checkPM(ctx.message): return userGame = await self.userGame(ctx.author) if not userGame: prefix = await self.bot.get_valid_prefixes() msg = f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`." return await self.sendToUser(ctx.author, msg) await self.showPlay(ctx, ctx.author) @commands.command() async def chat(self, ctx, *, message=None): """Broadcasts a message to the other players in your game.""" if not await self.checkPM(ctx.message): return userGame = await self.userGame(ctx.author) if not userGame: prefix = await self.bot.get_valid_prefixes() msg = f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`." return await self.sendToUser(ctx.author, msg) userGame["Time"] = int(time.time()) if message == None: msg = "Ooookay, you say *nothing...*" return await self.sendToUser(ctx.author, msg) msg = f"*{ctx.author.name}* says: {message}" for member in userGame["Members"]: if member["IsBot"]: continue # Tell them all!! if not member["User"] == ctx.author: # Don't tell yourself await self.sendToUser(member["User"], msg) else: # Update member's time member["Time"] = int(time.time()) await self.sendToUser(ctx.author, "Message sent!") @commands.command() async def lay(self, ctx, *, card=None): """Lays a card or cards from your hand. If multiple cards are needed, separate them by a comma (1,2,3).""" if not await self.checkPM(ctx.message): return userGame = await self.userGame(ctx.author) prefix = await self.bot.get_valid_prefixes() if not userGame: msg = f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`." return await self.sendToUser(ctx.author, msg) userGame["Time"] = int(time.time()) for member in userGame["Members"]: if member["User"] == ctx.author: member["Time"] = int(time.time()) user = member index = userGame["Members"].index(member) if index == userGame["Judge"]: await self.sendToUser(ctx.author, "You're the judge. You don't get to lay cards this round.") return for submit in userGame["Submitted"]: if submit["By"]["User"] == ctx.author: await self.sendToUser(ctx.author, "You already made your submission this round.") return if card == None: await self.sendToUser(ctx.author, "You need you input *something.*") return card = card.strip() card = card.replace(" ", "") # Not the judge if len(userGame["Members"]) < self.minMembers: stat_embed = discord.Embed(color=discord.Color.red()) stat_embed.set_author( name=f"Not enough players to continue! ({len(userGame['Members'])}/{self.minMembers})" ) stat_embed.set_footer(text=f"Have other users join with: {prefix[0]}joincah {userGame['ID']}") return await self.sendToUser(ctx.author, stat_embed, True) numberCards = userGame["BlackCard"]["Pick"] cards = [] if numberCards > 1: cardSpeak = "cards" try: card = card.split(",") except Exception: card = [] if not len(card) == numberCards: await self.sendToUser( ctx.author, f"You need to lay **{numberCards} cards** (no duplicates) with `{prefix[0]}lay [card numbers separated by commas (1,2,3)]`", ) return await self.showHand(ctx, ctx.author) # Got something # Check for duplicates if not len(card) == len(set(card)): await self.sendToUser( ctx.author, f"You need to lay **{numberCards} cards** (no duplicates) with `{prefix[0]}lay [card numbers separated by commas (1,2,3)]`", ) return await self.showHand(ctx, ctx.author) # Works for c in card: try: c = int(c) except Exception: await self.sendToUser( ctx.author, f"You need to lay **{numberCards} cards** (no duplicates) with `{prefix[0]}lay [card numbers separated by commas (1,2,3)]`", ) return await self.showHand(ctx, ctx.author) if c < 1 or c > len(user["Hand"]): await self.sendToUser(ctx.author, f"Card numbers must be between 1 and {len(user['Hand'])}.") return await self.showHand(ctx, ctx.author) cards.append(user["Hand"][c - 1]["Text"]) # Remove from user's hand card = sorted(card, key=lambda card: int(card), reverse=True) for c in card: user["Hand"].pop(int(c) - 1) # Valid cards newSubmission = {"By": user, "Cards": cards} else: cardSpeak = "card" try: card = int(card) except Exception: await self.sendToUser(ctx.author, f"You need to lay a valid card with `{prefix[0]}lay [card number]`") return await self.showHand(ctx, ctx.author) if card < 1 or card > len(user["Hand"]): await self.sendToUser(ctx.author, f"Card numbers must be between 1 and {len(user['Hand'])}.") return await self.showHand(ctx, ctx.author) # Valid card newSubmission = {"By": user, "Cards": [user["Hand"].pop(card - 1)["Text"]]} userGame["Submitted"].append(newSubmission) # Shuffle cards shuffle(userGame["Submitted"]) user["Laid"] = True await self.sendToUser(ctx.author, f"You submitted your {cardSpeak}!") await self.checkSubmissions(ctx, userGame, user) @commands.command() async def pick(self, ctx, *, card=None): """As the judge - pick the winning card(s).""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) prefix = await self.bot.get_valid_prefixes() if not userGame: # Not in a game msg = f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`." return await self.sendToUser(ctx.author, msg) userGame["Time"] = int(time.time()) isJudge = False for member in userGame["Members"]: if member["User"] == ctx.author: member["Time"] = int(time.time()) user = member index = userGame["Members"].index(member) if index == userGame["Judge"]: isJudge = True if not isJudge: msg = "You're not the judge - I guess you'll have to wait your turn." return await self.sendToUser(ctx.author, msg) # Am judge totalUsers = len(userGame["Members"]) - 1 submitted = len(userGame["Submitted"]) if submitted < totalUsers: if totalUsers - submitted == 1: msg = "Still waiting on 1 card..." else: msg = f"Still waiting on {totalUsers - submitted} cards..." await self.sendToUser(ctx.author, msg) return try: card = int(card) - 1 except Exception: card = -1 if card < 0 or card >= totalUsers: return await self.sendToUser(ctx.author, f"Your pick must be between 1 and {totalUsers}.") # Pick is good! await self.winningCard(ctx, userGame, card) @commands.command() async def hand(self, ctx): """Shows your hand.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) await self.showHand(ctx, ctx.author) userGame["Time"] = currentTime = int(time.time()) @commands.command() async def newcah(self, ctx): """Starts a new Cards Against Humanity game.""" try: embed = discord.Embed(color=discord.Color.green()) embed.set_author(name="**Setting up the game...**") await ctx.author.send(embed=embed) except discord.errors.Forbidden: return await ctx.send("You must allow Direct Messages from the bot for this game to work.") # Check if the user is already in game userGame = await self.userGame(ctx.author) if userGame: # Already in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're already in a game (id: *{userGame['ID']}*)\nType `{prefix[0]}leavecah` to leave that game.", ) # Not in a game - create a new one gameID = self.randomID() currentTime = int(time.time()) newGame = { "ID": gameID, "Members": [], "Discard": [], "BDiscard": [], "Judge": -1, "Time": currentTime, "BlackCard": None, "Submitted": [], "NextHand": asyncio.Event(), "Judging": False, "Timeout": True, } member = { "ID": ctx.author.id, "User": ctx.author, "Points": 0, "Won": [], "Hand": [], "Laid": False, "Refreshed": False, "IsBot": False, "Creator": True, "Task": None, "Time": currentTime, } newGame["Members"].append(member) newGame["Running"] = True task = self.bot.loop.create_task(self.gameCheckLoop(ctx, newGame)) task = self.bot.loop.create_task(self.checkCards(ctx, newGame)) self.games.append(newGame) # Tell the user they created a new game and list its ID await ctx.send(f"You created game id: *{gameID}*") await self.drawCards(ctx.author) # await self.showHand(ctx, ctx.author) # await self.nextPlay(ctx, newGame) @commands.command() async def leavecah(self, ctx): """Leaves the current game you're in.""" removeCheck = await self.removeMember(ctx.author) if not removeCheck: msg = "You are not in a game." await ctx.send(msg) return if self.checkGame(removeCheck): # await self.nextPlay(ctx, removeCheck) """# Start the game loop event = removeCheck['NextHand'] self.bot.loop.call_soon_threadsafe(event.set)""" # Player was removed - try to handle it calmly... await self.checkSubmissions(ctx, removeCheck) @commands.command() async def joincah(self, ctx, *, id=None): """Join a Cards Against Humanity game. If no id or user is passed, joins a random game.""" try: embed = discord.Embed(color=discord.Color.green()) embed.set_author(name="**Setting up the game...**") await ctx.author.send(embed=embed) except discord.errors.Forbidden: return await ctx.send("You must allow Direct Messages from the bot for this game to work.") # Check if the user is already in game userGame = await self.userGame(ctx.author) isCreator = False if userGame: # Already in a game prefix = await self.bot.get_valid_prefixes() return await ctx.send( f"You're already in a game (id: *{userGame['ID']}*)\nType `{prefix[0]}leavecah` to leave that game." ) if len(self.games): if id: game = self.gameForID(id) prefix = await self.bot.get_valid_prefixes() if game == None: # That id doesn't exist - or is possibly a user # If user, has to be joined from server chat if not ctx.message.guild: return await ctx.send( f"I couldn't find a game attached to that id. \n" f"If you are trying to join a user - run the `{prefix[0]}joincah [user]` " f"command in a channel in a Discord server you share with that user.\n" f"Make sure to use the proper command prefix for your server - it may or may not be `{prefix[0]}`." ) else: # We have a server - let's try for a user member = self.memberforname(id, ctx.message.guild) if not member: # Couldn't find user! return await ctx.send( f"I couldn't find a game attached to that id. \n" f"If you are trying to join a user - run the `{prefix[0]}joincah [user]` " f"command in a channel in a Discord server you share with that user.\n" f"Make sure to use the proper command prefix for your server - it may or may not be `{prefix[0]}`." ) # Have a user - check if they're in a game game = await self.userGame(member) if not game: # That user is NOT in a game! return await ctx.send("That user doesn't appear to be playing.") else: game = random.choice(self.games) else: # No games - create a new one gameID = self.randomID() currentTime = int(time.time()) game = { "ID": gameID, "Members": [], "Discard": [], "BDiscard": [], "Judge": -1, "Time": currentTime, "BlackCard": None, "Submitted": [], "NextHand": asyncio.Event(), "Judging": False, "Timeout": True, } game["Running"] = True task = self.bot.loop.create_task(self.gameCheckLoop(ctx, game)) task = self.bot.loop.create_task(self.checkCards(ctx, game)) self.games.append(game) # Tell the user they created a new game and list its ID await ctx.send(f"**You created game id:** ***{gameID}***") isCreator = True # Tell everyone else you joined for member in game["Members"]: if member["IsBot"]: continue await self.sendToUser(member["User"], f"***{self.displayname(ctx.author)}*** **joined the game!**") # We got a user! currentTime = int(time.time()) member = { "ID": ctx.author.id, "User": ctx.author, "Points": 0, "Won": [], "Hand": [], "Laid": False, "Refreshed": False, "IsBot": False, "Creator": isCreator, "Task": None, "Time": currentTime, } game["Members"].append(member) await self.drawCards(ctx.author) if len(game["Members"]) == 1: # Just created the game await self.drawCards(ctx.author) else: await ctx.send( f"**You've joined game id:** ***{game['ID']}!***\n\nThere are *{len(game['Members'])} users* in this game." ) # Check if adding put us at minimum members if len(game["Members"]) - 1 < self.minMembers: # It was - *actually* start a game event = game["NextHand"] self.bot.loop.call_soon_threadsafe(event.set) else: # It was not - just incorporate new players await self.checkSubmissions(ctx, game) # Reset judging flag to retrigger actions game["Judging"] = False # Show the user the current card and their hand await self.showPlay(ctx, member["User"]) await self.showHand(ctx, member["User"]) event = game["NextHand"] game["Time"] = int(time.time()) @commands.command() async def joinbot(self, ctx): """Adds a bot to the game. Can only be done by the player who created the game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) botCount = 0 for member in userGame["Members"]: if member["IsBot"]: botCount += 1 continue if member["User"] == ctx.author: if not member["Creator"]: # You didn't make this game msg = "Only the player that created the game can add bots." await self.sendToUser(ctx.author, msg) return member["Time"] = int(time.time()) # We are the creator - let's check the number of bots if botCount >= self.maxBots: # Too many bots! return await self.sendToUser(ctx.author, f"You already have enough bots (max is {self.maxBots}).") # We can get another bot! botID = self.randomBotID(userGame) lobot = { "ID": botID, "User": None, "Points": 0, "Won": [], "Hand": [], "Laid": False, "Refreshed": False, "IsBot": True, "Creator": False, "Task": None, } userGame["Members"].append(lobot) await self.drawCards(lobot["ID"]) for member in userGame["Members"]: if member["IsBot"]: continue await self.sendToUser(member["User"], f"***{self.botName} ({botID})*** **joined the game!**") # await self.nextPlay(ctx, userGame) # Check if adding put us at minimum members if len(userGame["Members"]) - 1 < self.minMembers: # It was - *actually* start a game event = userGame["NextHand"] self.bot.loop.call_soon_threadsafe(event.set) else: # It was not - just incorporate new players await self.checkSubmissions(ctx, userGame) # Reset judging flag to retrigger actions userGame["Judging"] = False # Schedule stuff task = asyncio.ensure_future(self.botPick(ctx, lobot, userGame)) lobot["Task"] = task @commands.command() async def joinbots(self, ctx, number=None): """Adds bots to the game. Can only be done by the player who created the game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) botCount = 0 for member in userGame["Members"]: if member["IsBot"]: botCount += 1 continue if member["User"] == ctx.author: if not member["Creator"]: # You didn't make this game return await self.sendToUser(ctx.author, "Only the player that created the game can add bots.") member["Time"] = int(time.time()) if number == None: # No number specified - let's add the max number of bots number = self.maxBots - botCount try: number = int(number) except ValueError: return await self.sendToUser(ctx.author, "Number of bots to add must be an integer.") # We are the creator - let's check the number of bots if botCount >= self.maxBots: # Too many bots! return await self.sendToUser(ctx.author, f"You already have enough bots (max is {self.maxBots}).") if number > (self.maxBots - botCount): number = self.maxBots - botCount if number == 1: msg = f"**Adding {number} bot:**\n\n" else: msg = f"**Adding {number} bots:**\n\n" newBots = [] for i in range(0, number): # We can get another bot! botID = self.randomBotID(userGame) lobot = { "ID": botID, "User": None, "Points": 0, "Won": [], "Hand": [], "Laid": False, "Refreshed": False, "IsBot": True, "Creator": False, "Task": None, } userGame["Members"].append(lobot) newBots.append(lobot) await self.drawCards(lobot["ID"]) msg += f"***{self.botName} ({botID})*** **joined the game!**\n" # await self.nextPlay(ctx, userGame) for member in userGame["Members"]: if member["IsBot"]: continue await self.sendToUser(member["User"], msg) # Check if adding put us at minimum members if len(userGame["Members"]) - number < self.minMembers: # It was - *actually* start a game event = userGame["NextHand"] self.bot.loop.call_soon_threadsafe(event.set) else: # It was not - just incorporate new players await self.checkSubmissions(ctx, userGame) # Reset judging flag to retrigger actions game["Judging"] = False for bot in newBots: # Schedule stuff task = asyncio.ensure_future(self.botPick(ctx, bot, userGame)) bot["Task"] = task @commands.command() async def removebot(self, ctx, *, id=None): """Removes a bot from the game. Can only be done by the player who created the game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) botCount = 0 for member in userGame["Members"]: if member["IsBot"]: botCount += 1 continue if member["User"] == ctx.author: if not member["Creator"]: # You didn't make this game return await self.sendToUser(ctx.author, "Only the player that created the game can remove bots.") member["Time"] = int(time.time()) # We are the creator - let's check the number of bots if id == None: # Just remove the first bot we find for member in userGame["Members"]: if member["IsBot"]: await self.removeMember(member["ID"]) """# Start the game loop event = userGame['NextHand'] self.bot.loop.call_soon_threadsafe(event.set)""" # Bot was removed - try to handle it calmly... return await self.checkSubmissions(ctx, userGame) msg = "No bots to remove!" return await self.sendToUser(ctx.author, msg) else: # Remove a bot by id if not await self.removeMember(id): # not found prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"I couldn't locate that bot on this game. If you're trying to remove a player, try the `{prefix[0]}removeplayer [name]` command.", ) # await self.nextPlay(ctx, userGame) """# Start the game loop event = userGame['NextHand'] self.bot.loop.call_soon_threadsafe(event.set)""" # Bot was removed - let's try to handle it calmly... await self.checkSubmissions(ctx, userGame) @commands.command() async def cahgames(self, ctx): """Displays up to 10 CAH games in progress.""" shuffledGames = list(self.games) random.shuffle(shuffledGames) if not len(shuffledGames): await ctx.send("No games being played currently.") return max = 10 if len(shuffledGames) < 10: max = len(shuffledGames) msg = "__Current CAH Games__:\n\n" for i in range(0, max): playerCount = 0 botCount = 0 gameID = shuffledGames[i]["ID"] for j in shuffledGames[i]["Members"]: if j["IsBot"]: botCount += 1 else: playerCount += 1 botText = f"{botCount} bot" if not botCount == 1: botText += "s" playerText = f"{playerCount} player" if not playerCount == 1: playerText += "s" msg += f"{i + 1}. {gameID} - {playerText} | {botText}\n" await ctx.send(msg) @commands.command() async def score(self, ctx): """Display the score of the current game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) stat_embed = discord.Embed(color=discord.Color.purple()) stat_embed.set_author(name="Current Score") stat_embed.set_footer(text=f"Cards Against Humanity - id: {userGame['ID']}") await self.sendToUser(ctx.author, stat_embed, True) users = sorted(userGame["Members"], key=lambda card: int(card["Points"]), reverse=True) msg = "" i = 0 if len(users) > 10: msg += f"__10 of {len(users)} Players:__\n\n" else: msg += "__Players:__\n\n" for user in users: i += 1 if i > 10: break if user["Points"] == 1: if user["User"]: # Person msg += f"{i}. *{self.displayname(user['User'])}* - 1 point\n" else: # Bot msg += f"{i}. *{self.botName} ({user['ID']})* - 1 point\n" else: if user["User"]: # Person msg += f"{i}. *{self.displayname(user['User'])}* - {user['Points']} points\n" else: # Bot msg += f"{i}. *{self.botName} ({user['ID']})* - {user['Points']} points\n" await self.sendToUser(ctx.author, msg) @commands.command() async def laid(self, ctx): """Shows who laid their cards and who hasn't.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) stat_embed = discord.Embed(color=discord.Color.purple()) stat_embed.set_author(name="Card Check") stat_embed.set_footer(text=f"Cards Against Humanity - id: {userGame['ID']}") await self.sendToUser(ctx.author, stat_embed, True) users = sorted(userGame["Members"], key=lambda card: int(card["Laid"])) msg = "" i = 0 if len(users) > 10: msg += f"__10 of {len(users)} Players:__\n\n" else: msg += "__Players:__\n\n" for user in users: if len(userGame["Members"]) >= self.minMembers: if user == userGame["Members"][userGame["Judge"]]: continue i += 1 if i > 10: break if user["Laid"]: if user["User"]: # Person msg += f"{i}. *{self.displayname(user['User'])}* - Cards are in.\n" else: # Bot msg += f"{i}. *{self.botName} ({user['ID']})* - Cards are in.\n" else: if user["User"]: # Person msg += f"{i}. *{self.displayname(user['User'])}* - Waiting for cards...\n" else: # Bot msg += f"{i}. *{self.botName} ({user['ID']})* - Waiting for cards...\n" await self.sendToUser(ctx.author, msg) @commands.command() async def removeplayer(self, ctx, *, name=None): """Removes a player from the game. Can only be done by the player who created the game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) botCount = 0 for member in userGame["Members"]: if member["IsBot"]: botCount += 1 continue if member["User"] == ctx.author: if not member["Creator"]: # You didn't make this game return await self.sendToUser( ctx.author, "Only the player that created the game can remove players." ) member["Time"] = int(time.time()) # We are the creator - let's check the number of bots if name == None: # Nobody named! return await self.sendToUser(ctx.author, "Okay, I removed... no one from the game...") # Let's get the person either by name, or by id nameID = "".join(list(filter(str.isdigit, name))) for member in userGame["Members"]: toRemove = False if member["IsBot"]: continue if name.lower() == self.displayname(member["User"]).lower(): # Got em! toRemove = True elif nameID == member["ID"]: # Got em! toRemove = True if toRemove: await self.removeMember(member["ID"]) break # await self.nextPlay(ctx, userGame) if toRemove: """# Start the game loop event = userGame['NextHand'] self.bot.loop.call_soon_threadsafe(event.set)""" # Player was removed - try to handle it calmly... await self.checkSubmissions(ctx, userGame) else: prefix = await self.bot.get_valid_prefixes() msg = f"I couldn't locate that player on this game. If you're trying to remove a bot, try the `{prefix[0]}removebot [id]` command." await self.sendToUser(ctx.author, msg) @commands.command() async def flushhand(self, ctx): """Flushes the cards in your hand - can only be done once per game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) if userGame["Judge"] == -1: msg = "The game hasn't started yet. Probably not worth it to flush your hand before you get it..." return await self.sendToUser(ctx.author, msg) for member in userGame["Members"]: if member["IsBot"]: continue if member["User"] == ctx.author: member["Time"] = int(time.time()) # Found us! if member["Refreshed"]: # Already flushed their hand msg = "You have already flushed your hand this game." return await self.sendToUser(ctx.author, msg) else: member["Hand"] = [] await self.drawCards(member["ID"]) member["Refreshed"] = True await self.sendToUser(ctx.author, "Flushing your hand!") await self.showHand(ctx, ctx.author) return @commands.command() async def idlekick(self, ctx, *, setting=None): """Sets whether or not to kick members if idle for 5 minutes or more. Can only be done by the player who created the game.""" if not await self.checkPM(ctx.message): return # Check if the user is already in game userGame = await self.userGame(ctx.author) if not userGame: # Not in a game prefix = await self.bot.get_valid_prefixes() return await self.sendToUser( ctx.author, f"You're not in a game - you can create one with `{prefix[0]}newcah` or join one with `{prefix[0]}joincah`.", ) botCount = 0 for member in userGame["Members"]: if member["IsBot"]: botCount += 1 continue if member["User"] == ctx.author: if not member["Creator"]: # You didn't make this game return await self.sendToUser(ctx.author, "Only the player that created the game can remove bots.") # We are the creator - let's check the number of bots if setting == None: # Output idle kick status if userGame["Timeout"]: await ctx.send("Idle kick is enabled.") else: await ctx.send("Idle kick is disabled.") return elif setting.lower() == "yes" or setting.lower() == "on" or setting.lower() == "true": setting = True elif setting.lower() == "no" or setting.lower() == "off" or setting.lower() == "false": setting = False else: setting = None if setting == True: if userGame["Timeout"] == True: msg = "Idle kick remains enabled." else: msg = "Idle kick now enabled." for member in userGame["Members"]: member["Time"] = int(time.time()) else: if userGame["Timeout"] == False: msg = "Idle kick remains disabled." else: msg = "Idle kick now disabled." userGame["Timeout"] = setting await ctx.send(msg) @commands.command() async def cahcredits(self, ctx): """Code credits.""" await ctx.send( "```\nThis cog is made possible by CorpBot.\nPlease visit https://github.com/corpnewt/CorpBot.py for more information.\n```" )