Files
aikaterna-cogs/cah/cah.py
2020-01-01 14:57:07 -08:00

1844 lines
73 KiB
Python

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
BaseCog = getattr(commands, "Cog", object)
class CardsAgainstHumanity(BaseCog):
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("<br>", "\n")
json = json.replace("<br/>", "\n")
json = json.replace("<i>", "*")
json = json.replace("</i>", "*")
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 = "{}{} week, ".format(msg, str(weeks))
else:
msg = "{}{} weeks, ".format(msg, str(weeks))
if days > 0:
if days == 1:
msg = "{}{} day, ".format(msg, str(days))
else:
msg = "{}{} days, ".format(msg, str(days))
if hours > 0:
if hours == 1:
msg = "{}{} hour, ".format(msg, str(hours))
else:
msg = "{}{} hours, ".format(msg, str(hours))
if minutes > 0:
if minutes == 1:
msg = "{}{} minute, ".format(msg, str(minutes))
else:
msg = "{}{} minutes, ".format(msg, str(minutes))
if seconds > 0:
if seconds == 1:
msg = "{}{} second, ".format(msg, str(seconds))
else:
msg = "{}{} seconds, ".format(msg, str(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)
msg = "**WARNING** - You will be kicked from the game if you do not make a move in *{}!*".format(
timeString
)
await member["User"].send(msg)
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
msg = "Game id: *{}* has been closed due to inactivity.".format(game["ID"])
await member["User"].send(msg)
# 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 PM.")
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 newCreator["User"].send(
"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:
msg = "**You were removed from game id:** ***{}.***".format(game["ID"])
await member["User"].send(msg)
# 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 = "***{} ({})*** **left the game - reorganizing...**".format(
self.botName, removed["ID"]
)
else:
msg = "***{}*** **left the game - reorganizing...**".format(
self.displayname(removed["User"])
)
# Check if the judge changed
if judgeChanged:
# Judge changed
newJudge = game["Members"][game["Judge"]]
if newJudge["IsBot"]:
msg += "\n\n***{} ({})*** **is now judging!**".format(
self.botName, newJudge["ID"]
)
# Schedule judging task
else:
if newJudge == member:
msg += "\n\n***YOU*** **are now judging!**"
else:
msg += "\n\n***{}*** **is now judging!**".format(
self.displayname(newJudge["User"])
)
await member["User"].send(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
prefix = await self.bot.db.prefix()
stat_embed = discord.Embed(color=discord.Color.red())
stat_embed.set_author(
name="Not enough players to continue! ({}/{})".format(
len(game["Members"]), self.minMembers
)
)
stat_embed.set_footer(
text="Have other users join with: {}joincah {}".format(prefix[0], game["ID"])
)
await member["User"].send(embed=stat_embed)
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 = "*{} ({})* submitted their {}! ".format(self.botName, user["ID"], card)
else:
if not member == user:
# Don't say this to the submitting user
msg = "*{}* submitted their {}! ".format(
self.displayname(user["User"]), card
)
if submitted < totalUsers:
msg += "{}/{} cards submitted...".format(submitted, totalUsers)
if len(msg):
# We have something to say
await member["User"].send(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 member["User"].send(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 = "{} ({})".format(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="Cards Against Humanity - id: {}".format(game["ID"]))
index = game["Members"].index(member)
if index == game["Judge"]:
stat_embed.set_author(name="You picked {}'s card!".format(winnerName))
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="{} won!".format(winnerName))
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 member["User"].send(embed=stat_embed)
await member["User"].send(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 member["User"].send(message)
else:
# Not the judge
await member["User"].send(message)
################################################
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 = "*{} ({})* is".format(self.botName, game["Members"][game["Judge"]]["ID"])
else:
judge = "*{}* is".format(self.displayname(game["Members"][game["Judge"]]["User"]))
# Get the Black Card
try:
blackCard = game["BlackCard"]["Text"]
blackNum = game["BlackCard"]["Pick"]
except Exception:
blackCard = "None."
blackNum = 0
msg = "{} the judge.\n\n".format(judge)
msg += "__Black Card:__\n\n**{}**\n\n".format(blackCard)
totalUsers = len(game["Members"]) - 1
submitted = len(game["Submitted"])
if len(game["Members"]) >= self.minMembers:
if submitted < totalUsers:
msg += "{}/{} cards submitted...".format(submitted, totalUsers)
else:
msg += "All cards have been submitted!"
await self.showOptions(ctx, user)
return
prefix = await self.bot.db.prefix()
if not judge == "**YOU** are":
# Judge doesn't need to lay a card
if blackNum == 1:
# Singular
msg += "\n\nLay a card with `{}lay [card number]`".format(prefix[0])
elif blackNum > 1:
# Plural
msg += "\n\nLay **{} cards** with `{}lay [card numbers separated by commas (1,2,3)]`".format(
blackNum, prefix[0]
)
stat_embed.set_author(name="Current Play")
stat_embed.set_footer(text="Cards Against Humanity - id: {}".format(game["ID"]))
await user.send(embed=stat_embed)
await user.send(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 = "{} points".format(member["Points"])
for card in member["Hand"]:
i += 1
msg += "{}. {}\n".format(i, card["Text"])
try:
blackCard = "**{}**".format(game["BlackCard"]["Text"])
except Exception:
blackCard = "**None.**"
stat_embed.set_author(name="Your Hand - {}".format(points))
stat_embed.set_footer(text="Cards Against Humanity - id: {}".format(game["ID"]))
await user.send(embed=stat_embed)
await user.send(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="Cards Against Humanity - id: {}".format(game["ID"]))
await user.send(embed=stat_embed)
if game["Members"][game["Judge"]]["User"] == user:
judge = "**YOU** are"
else:
if game["Members"][game["Judge"]]["IsBot"]:
# Bot
judge = "*{} ({})* is".format(self.botName, game["Members"][game["Judge"]]["ID"])
else:
judge = "*{}* is".format(self.displayname(game["Members"][game["Judge"]]["User"]))
blackCard = game["BlackCard"]["Text"]
msg = "{} judging.\n\n".format(judge)
msg += "__Black Card:__\n\n**{}**\n\n".format(blackCard)
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.db.prefix()
msg += "\nPick a winner with `{}pick [submission number]`.".format(prefix[0])
await user.send(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 user.send("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 user.send("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:
prefix = await self.bot.db.prefix()
stat_embed = discord.Embed(color=discord.Color.red())
stat_embed.set_author(
name="Not enough players to continue! ({}/{})".format(
len(game["Members"]), self.minMembers
)
)
stat_embed.set_footer(
text="Have other users join with: {}joincah {}".format(prefix[0], game["ID"])
)
for member in game["Members"]:
if member["IsBot"]:
continue
await member["User"].send(embed=stat_embed)
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="{} ({}) is the WINNER!!".format(self.botName, member["ID"])
)
else:
stat_embed.set_author(
name="{} is the WINNER!!".format(self.displayname(member["User"]))
)
stat_embed.set_footer(text="Congratulations!".format(game["ID"]))
break
if winner:
for member in game["Members"]:
if not member["IsBot"]:
await member["User"].send(embed=stat_embed)
# 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.message.author)
if not userGame:
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
await self.showPlay(ctx, ctx.message.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.message.author)
if not userGame:
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
userGame["Time"] = int(time.time())
if message == None:
msg = "Ooookay, you say *nothing...*"
await ctx.message.author.send(msg)
return
msg = "*{}* says: {}".format(ctx.message.author.name, message)
for member in userGame["Members"]:
if member["IsBot"]:
continue
# Tell them all!!
if not member["User"] == ctx.message.author:
# Don't tell yourself
await member["User"].send(msg)
else:
# Update member's time
member["Time"] = int(time.time())
await ctx.message.author.send("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
prefix = await self.bot.db.prefix()
userGame = await self.userGame(ctx.message.author)
if not userGame:
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
userGame["Time"] = int(time.time())
for member in userGame["Members"]:
if member["User"] == ctx.message.author:
member["Time"] = int(time.time())
user = member
index = userGame["Members"].index(member)
if index == userGame["Judge"]:
await ctx.message.author.send(
"You're the judge. You don't get to lay cards this round."
)
return
for submit in userGame["Submitted"]:
if submit["By"]["User"] == ctx.message.author:
await ctx.message.author.send("You already made your submission this round.")
return
if card == None:
await ctx.message.author.send("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="Not enough players to continue! ({}/{})".format(
len(userGame["Members"]), self.minMembers
)
)
stat_embed.set_footer(
text="Have other users join with: {}joincah {}".format(prefix[0], userGame["ID"])
)
await ctx.message.author.send(embed=stat_embed)
return
numberCards = userGame["BlackCard"]["Pick"]
cards = []
if numberCards > 1:
cardSpeak = "cards"
try:
card = card.split(",")
except Exception:
card = []
if not len(card) == numberCards:
msg = "You need to lay **{} cards** (no duplicates) with `{}lay [card numbers separated by commas (1,2,3)]`".format(
numberCards, prefix[0]
)
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
# Got something
# Check for duplicates
if not len(card) == len(set(card)):
msg = "You need to lay **{} cards** (no duplicates) with `{}lay [card numbers separated by commas (1,2,3)]`".format(
numberCards, prefix[0]
)
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
# Works
for c in card:
try:
c = int(c)
except Exception:
msg = "You need to lay **{} cards** (no duplicates) with `{}lay [card numbers separated by commas (1,2,3)]`".format(
numberCards, prefix[0]
)
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
if c < 1 or c > len(user["Hand"]):
msg = "Card numbers must be between 1 and {}.".format(len(user["Hand"]))
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
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:
msg = "You need to lay a valid card with `{}lay [card number]`".format(prefix[0])
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
if card < 1 or card > len(user["Hand"]):
msg = "Card numbers must be between 1 and {}.".format(len(user["Hand"]))
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.author)
return
# 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 ctx.message.author.send("You submitted your {}!".format(cardSpeak))
await self.checkSubmissions(ctx, userGame, user)
@commands.command()
async def pick(self, ctx, *, card=None):
"""As the judge - pick the winning card(s)."""
prefix = await self.bot.db.prefix()
if not await self.checkPM(ctx.message):
return
# Check if the user is already in game
userGame = await self.userGame(ctx.message.author)
if not userGame:
# Not in a game
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
userGame["Time"] = int(time.time())
isJudge = False
for member in userGame["Members"]:
if member["User"] == ctx.message.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.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
# 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 = "Still waiting on {} cards...".format(totalUsers - submitted)
await ctx.message.author.send(msg)
return
try:
card = int(card) - 1
except Exception:
card = -1
if card < 0 or card >= totalUsers:
msg = "Your pick must be between 1 and {}.".format(totalUsers)
await ctx.message.author.send(msg)
return
# 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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
await self.showHand(ctx, ctx.message.author)
userGame["Time"] = currentTime = int(time.time())
@commands.command()
async def newcah(self, ctx):
"""Starts a new Cards Against Humanity game."""
# if not await self.checkPM(ctx.message):
# return
# Check if the user is already in game
prefix = await self.bot.db.prefix()
userGame = await self.userGame(ctx.message.author)
if userGame:
# Already in a game
msg = "You're already in a game (id: *{}*)\nType `{}leavecah` to leave that game.".format(
userGame["ID"], prefix[0]
)
await ctx.message.author.send(msg)
return
# 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.message.author.id,
"User": ctx.message.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.message.channel.send("You created game id: *{}*".format(gameID))
await self.drawCards(ctx.message.author)
# await self.showHand(ctx, ctx.message.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.message.author)
if not removeCheck:
msg = "You are not in a game."
await ctx.message.channel.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."""
# if not await self.checkPM(ctx.message):
# return
# Check if the user is already in game
prefix = await self.bot.db.prefix()
userGame = await self.userGame(ctx.message.author)
isCreator = False
if userGame:
# Already in a game
msg = "You're already in a game (id: *{}*)\nType `{}leavecah` to leave that game.".format(
userGame["ID"], prefix[0]
)
await ctx.message.channel.send(msg)
return
if len(self.games):
if id:
game = self.gameForID(id)
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:
msg = "I couldn't find a game attached to that id. If you are trying to join a user - run the `{}joincah [user]` command in a channel on a server you share with that user.".format(
prefix[0]
)
await ctx.message.channel.send(msg)
return
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!
msg = "I couldn't find a game attached to that id. If you are trying to join a user - run the `{}joincah [user]` command in a channel on a server you share with that user.".format(
prefix[0]
)
await ctx.message.channel.send(msg)
return
# 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!
msg = "That user doesn't appear to be playing."
await ctx.message.channel.send(msg)
return
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.message.channel.send("**You created game id:** ***{}***".format(gameID))
isCreator = True
# Tell everyone else you joined
for member in game["Members"]:
if member["IsBot"]:
continue
await member["User"].send(
"***{}*** **joined the game!**".format(self.displayname(ctx.message.author))
)
# We got a user!
currentTime = int(time.time())
member = {
"ID": ctx.message.author.id,
"User": ctx.message.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.message.author)
if len(game["Members"]) == 1:
# Just created the game
await self.drawCards(ctx.message.author)
else:
msg = "**You've joined game id:** ***{}!***\n\nThere are *{} users* in this game.".format(
game["ID"], len(game["Members"])
)
await ctx.message.channel.send(msg)
# 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
prefix = await self.bot.db.prefix()
userGame = await self.userGame(ctx.message.author)
if not userGame:
# Not in a game
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
botCount = 0
for member in userGame["Members"]:
if member["IsBot"]:
botCount += 1
continue
if member["User"] == ctx.message.author:
if not member["Creator"]:
# You didn't make this game
msg = "Only the player that created the game can add bots."
await ctx.message.author.send(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!
msg = "You already have enough bots (max is {}).".format(self.maxBots)
await ctx.message.author.send(msg)
return
# 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"])
msg = "***{} ({})*** **joined the game!**".format(self.botName, botID)
for member in userGame["Members"]:
if member["IsBot"]:
continue
await member["User"].send(msg)
# 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
prefix = await self.bot.db.prefix()
# Check if the user is already in game
userGame = await self.userGame(ctx.message.author)
if not userGame:
# Not in a game
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
botCount = 0
for member in userGame["Members"]:
if member["IsBot"]:
botCount += 1
continue
if member["User"] == ctx.message.author:
if not member["Creator"]:
# You didn't make this game
msg = "Only the player that created the game can add bots."
await ctx.message.author.send(msg)
return
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 Exception:
msg = "Number of bots to add must be an integer."
await ctx.message.author.send(msg)
return
# We are the creator - let's check the number of bots
if botCount >= self.maxBots:
# Too many bots!
msg = "You already have enough bots (max is {}).".format(self.maxBots)
await ctx.message.author.send(msg)
return
if number > (self.maxBots - botCount):
number = self.maxBots - botCount
if number == 1:
msg = "**Adding {} bot:**\n\n".format(number)
else:
msg = "**Adding {} bots:**\n\n".format(number)
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 += "***{} ({})*** **joined the game!**\n".format(self.botName, botID)
# await self.nextPlay(ctx, userGame)
for member in userGame["Members"]:
if member["IsBot"]:
continue
await member["User"].send(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
prefix = await self.bot.db.prefix()
userGame = await self.userGame(ctx.message.author)
if not userGame:
# Not in a game
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
botCount = 0
for member in userGame["Members"]:
if member["IsBot"]:
botCount += 1
continue
if member["User"] == ctx.message.author:
if not member["Creator"]:
# You didn't make this game
msg = "Only the player that created the game can remove bots."
await ctx.message.author.send(msg)
return
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...
await self.checkSubmissions(ctx, userGame)
return
msg = "No bots to remove!"
await ctx.message.author.send(msg)
return
else:
# Remove a bot by id
if not await self.removeMember(id):
# not found
msg = "I couldn't locate that bot on this game. If you're trying to remove a player, try the `{}removeplayer [name]` command.".format(
prefix[0]
)
await ctx.message.author.send(msg)
return
# 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.message.channel.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 = "{} bot".format(botCount)
if not botCount == 1:
botText += "s"
playerText = "{} player".format(playerCount)
if not playerCount == 1:
playerText += "s"
msg += "{}. {} - {} | {}\n".format(i + 1, gameID, playerText, botText)
await ctx.message.channel.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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
stat_embed = discord.Embed(color=discord.Color.purple())
stat_embed.set_author(name="Current Score")
stat_embed.set_footer(text="Cards Against Humanity - id: {}".format(userGame["ID"]))
await ctx.message.author.send(embed=stat_embed)
users = sorted(userGame["Members"], key=lambda card: int(card["Points"]), reverse=True)
msg = ""
i = 0
if len(users) > 10:
msg += "__10 of {} Players:__\n\n".format(len(users))
else:
msg += "__Players:__\n\n"
for user in users:
i += 1
if i > 10:
break
if user["Points"] == 1:
if user["User"]:
# Person
msg += "{}. *{}* - 1 point\n".format(i, self.displayname(user["User"]))
else:
# Bot
msg += "{}. *{} ({})* - 1 point\n".format(i, self.botName, user["ID"])
else:
if user["User"]:
# Person
msg += "{}. *{}* - {} points\n".format(
i, self.displayname(user["User"]), user["Points"]
)
else:
# Bot
msg += "{}. *{} ({})* - {} points\n".format(
i, self.botName, user["ID"], user["Points"]
)
await ctx.message.author.send(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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
stat_embed = discord.Embed(color=discord.Color.purple())
stat_embed.set_author(name="Card Check")
stat_embed.set_footer(text="Cards Against Humanity - id: {}".format(userGame["ID"]))
await ctx.message.author.send(embed=stat_embed)
users = sorted(userGame["Members"], key=lambda card: int(card["Laid"]))
msg = ""
i = 0
if len(users) > 10:
msg += "__10 of {} Players:__\n\n".format(len(users))
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 += "{}. *{}* - Cards are in.\n".format(i, self.displayname(user["User"]))
else:
# Bot
msg += "{}. *{} ({})* - Cards are in.\n".format(i, self.botName, user["ID"])
else:
if user["User"]:
# Person
msg += "{}. *{}* - Waiting for cards...\n".format(
i, self.displayname(user["User"])
)
else:
# Bot
msg += "{}. *{} ({})* - Waiting for cards...\n".format(
i, self.botName, user["ID"]
)
await ctx.message.author.send(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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
botCount = 0
for member in userGame["Members"]:
if member["IsBot"]:
botCount += 1
continue
if member["User"] == ctx.message.author:
if not member["Creator"]:
# You didn't make this game
msg = "Only the player that created the game can remove players."
await ctx.message.author.send(msg)
return
member["Time"] = int(time.time())
# We are the creator - let's check the number of bots
if name == None:
# Nobody named!
msg = "Okay, I removed... no one from the game..."
await ctx.message.author.send(msg)
return
# 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.db.prefix()
msg = "I couldn't locate that player on this game. If you're trying to remove a bot, try the `{}removebot [id]` command.".format(
prefix[0]
)
await ctx.message.author.send(msg)
return
@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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
if userGame["Judge"] == -1:
msg = "The game hasn't started yet. Probably not worth it to flush your hand before you get it..."
await ctx.message.author.send(msg)
return
for member in userGame["Members"]:
if member["IsBot"]:
continue
if member["User"] == ctx.message.author:
member["Time"] = int(time.time())
# Found us!
if member["Refreshed"]:
# Already flushed their hand
msg = "You have already flushed your hand this game."
await ctx.message.author.send(msg)
return
else:
member["Hand"] = []
await self.drawCards(member["ID"])
member["Refreshed"] = True
msg = "Flushing your hand!"
await ctx.message.author.send(msg)
await self.showHand(ctx, ctx.message.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.message.author)
if not userGame:
# Not in a game
prefix = await self.bot.db.prefix()
msg = "You're not in a game - you can create one with `{}newcah` or join one with `{}joincah`.".format(
prefix[0], prefix[0]
)
await ctx.message.author.send(msg)
return
botCount = 0
for member in userGame["Members"]:
if member["IsBot"]:
botCount += 1
continue
if member["User"] == ctx.message.author:
if not member["Creator"]:
# You didn't make this game
msg = "Only the player that created the game can remove bots."
await ctx.message.author.send(msg)
return
# We are the creator - let's check the number of bots
if setting == None:
# Output idle kick status
if userGame["Timeout"]:
await ctx.message.channel.send("Idle kick is enabled.")
else:
await ctx.message.channel.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.message.channel.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```"
)