import asyncio
import discord
import re
import os
import random
import string
import json
import time
import html
import codecs
from random import shuffle
from discord.ext import commands
class CardsAgainstHumanity:
# Init with the bot reference, and a reference to the deck file
def __init__(self, bot, file = None):
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 = 300 # 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.loopsleep = 0.05
if file == None:
file = "data/cah/deck.json"
# Let's load our deck file
# Can be found at http://www.crhallberg.com/cah/json
if os.path.exists(file):
f = open(file,'r')
filedata = f.read()
f.close()
self.deck = json.loads(filedata)
else:
# File doesn't exist - create a placeholder
self.deck = {}
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 = memberForID(memID, server)
if newMem:
return newMem
return None
def getreadabletimebetween(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 not self.bot.is_closed:
# 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 self.bot.send_message(member['User'], msg)
else:
for member in game['Members']:
# Reset timer
member['Time'] = int(time.time())
async def checkDead(self):
while not self.bot.is_closed:
# 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 self.bot.send_message(member['User'], 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 message.channel.is_private:
# PM
return True
else:
# Not in PM
await self.bot.send_message(message.channel, '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
def userGame(self, user):
# Returns the game the user is currently in
if not type(user) is str:
# 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 type(user) is str:
# Assume it's a discord.Member/User
user = user.id
outcome = False
removed = None
if not game:
game = 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.bot.send_message(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:
msg = '**You were removed from game id:** ***{}.***'.format(game['ID'])
await self.bot.send_message(member['User'], 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 self.bot.send_message(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
# Show that we're typing
await self.bot.send_typing(member['User'])
await asyncio.sleep(self.loopsleep)
await asyncio.sleep(typeTime)
else:
for member in game['Members']:
if member['IsBot']:
continue
# Show that we're typing
await self.bot.send_typing(member['User'])
await asyncio.sleep(self.loopsleep)
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='Not enough players to continue! ({}/{})'.format(len(game['Members']), self.minMembers))
stat_embed.set_footer(text='Have other users join with: {}joincah {}'.format(ctx.prefix, game['ID']))
await self.bot.send_message(member['User'], 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 self.bot.send_message(member['User'], msg)
await asyncio.sleep(self.loopsleep)
async def checkCards(self, ctx, game):
while not self.bot.is_closed:
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.bot.send_message(member['User'], msg)
await self.showOptions(ctx, member['User'])
await asyncio.sleep(self.loopsleep)
# 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 self.bot.send_message(member['User'], embed=stat_embed)
await self.bot.send_message(member['User'], msg)
await asyncio.sleep(self.loopsleep)
# 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.bot.send_message(member['User'], message)
else:
# Not the judge
await self.bot.send_message(member['User'], 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 = 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
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(ctx.prefix)
elif blackNum > 1:
# Plural
msg += '\n\nLay **{} cards** with `{}lay [card numbers separated by commas (1,2,3)]`'.format(blackNum, ctx.prefix)
stat_embed.set_author(name='Current Play')
stat_embed.set_footer(text='Cards Against Humanity - id: {}'.format(game['ID']))
await self.bot.send_message(user, embed=stat_embed)
await self.bot.send_message(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 = 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 self.bot.send_message(user, embed=stat_embed)
await self.bot.send_message(user, msg)
async def showOptions(self, ctx, user):
# Shows the judgement options
stat_embed = discord.Embed(color=discord.Color.orange())
game = 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 self.bot.send_message(user, 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':
msg += '\nPick a winner with `{}pick [submission number]`.'.format(ctx.prefix)
await self.bot.send_message(user, msg)
async def drawCard(self, game):
# 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(self.deck['whiteCards']):
# Tell everyone the cards were shuffled
for member in game['Members']:
if member['IsBot']:
continue
user = member['User']
await self.bot.send_message(user, 'Shuffling white cards...')
# Shuffle the cards
self.shuffle(game)
while True:
# Random grab a unique card
index = random.randint(0, len(self.deck['whiteCards'])-1)
if not index in game['Discard']:
game['Discard'].append(index)
text = self.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 type(user) is str:
# Assume it's a discord.Member/User
user = user.id
# fills the user's hand up to number of cards
game = 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):
# Draws a random black card
totalDiscard = len(game['BDiscard'])
if totalDiscard >= len(self.deck['blackCards']):
# Tell everyone the cards were shuffled
for member in game['Members']:
if member['IsBot']:
continue
user = member['User']
await self.bot.send_message(user, 'Shuffling black cards...')
# Shuffle the cards
game['BDiscard'] = []
while True:
# Random grab a unique card
index = random.randint(0, len(self.deck['blackCards'])-1)
if not index in game['BDiscard']:
game['BDiscard'].append(index)
text = self.deck['blackCards'][index]['text']
text = self.cleanJson(text)
game['BlackCard'] = { 'Text': text, 'Pick': self.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='Not enough players to continue! ({}/{})'.format(len(game['Members']), self.minMembers))
stat_embed.set_footer(text='Have other users join with: {}joincah {}'.format(ctx.prefix, game['ID']))
for member in game['Members']:
if member['IsBot']:
continue
await self.bot.send_message(member['User'], 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 self.bot.send_message(member['User'], embed=stat_embed)
# Reset all users
member['Hand'] = []
member['Points'] = 0
member['Won'] = []
member['Laid'] = False
member['Refreshed'] = False
await asyncio.sleep(self.loopsleep)
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(self.loopsleep)
# 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(pass_context=True)
async def game(self, ctx, *, message = None):
"""Displays the game's current status."""
if not await self.checkPM(ctx.message):
return
userGame = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, msg)
return
await self.showPlay(ctx, ctx.message.author)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, msg)
return
userGame['Time'] = int(time.time())
if message == None:
msg = "Ooookay, you say *nothing...*"
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(member['User'], msg)
else:
# Update member's time
member['Time'] = int(time.time())
await self.bot.send_message(ctx.message.author, 'Message sent!')
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.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.message.author:
await self.bot.send_message(ctx.message.author, "You already made your submission this round.")
return
if card == None:
await self.bot.send_message(ctx.message.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='Not enough players to continue! ({}/{})'.format(len(userGame['Members']), self.minMembers))
stat_embed.set_footer(text='Have other users join with: {}joincah {}'.format(ctx.prefix, userGame['ID']))
await self.bot.send_message(ctx.message.author, 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, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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(ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 'You submitted your {}!'.format(cardSpeak))
await self.checkSubmissions(ctx, userGame, user)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, msg)
return
# Pick is good!
await self.winningCard(ctx, userGame, card)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, msg)
return
await self.showHand(ctx, ctx.message.author)
userGame['Time'] = currentTime = int(time.time())
@commands.command(pass_context=True)
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
userGame = 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'], ctx.prefix)
await self.bot.send_message(ctx.message.channel, 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 self.bot.send_message(ctx.message.channel, '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(pass_context=True)
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 self.bot.send_message(ctx.message.channel, 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(pass_context=True)
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
userGame = 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'], ctx.prefix)
await self.bot.send_message(ctx.message.channel, 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.server:
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(ctx.prefix)
await self.bot.send_message(ctx.message.channel, msg)
return
else:
# We have a server - let's try for a user
member = self.memberforname(id, ctx.message.server)
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(ctx.prefix)
await self.bot.send_message(ctx.message.channel, msg)
return
# Have a user - check if they're in a game
game = self.userGame(member)
if not game:
# That user is NOT in a game!
msg = "That user doesn't appear to be playing."
await self.bot.send_message(ctx.message.channel, 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 self.bot.send_message(ctx.message.channel, '**You created game id:** ***{}***'.format(gameID))
isCreator = True
# Tell everyone else you joined
for member in game['Members']:
if member['IsBot']:
continue
await self.bot.send_message(member['User'], '***{}*** **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 self.bot.send_message(ctx.message.channel, 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(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.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!
msg = 'You already have enough bots (max is {}).'.format(self.maxBots)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(member['User'], 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(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(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(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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(ctx.prefix)
await self.bot.send_message(ctx.message.author, 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(pass_context=True)
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 self.bot.send_message(ctx.message.channel, '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 self.bot.send_message(ctx.message.channel, msg)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, msg)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, msg)
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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:
msg = 'I couldn\'t locate that player on this game. If you\'re trying to remove a bot, try the `{}removebot [id]` command.'.format(ctx.prefix)
await self.bot.send_message(ctx.message.author, msg)
return
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, msg)
return
else:
member['Hand'] = []
await self.drawCards(member['ID'])
member['Refreshed'] = True
msg = 'Flushing your hand!'
await self.bot.send_message(ctx.message.author, msg)
await self.showHand(ctx, ctx.message.author)
return
@commands.command(pass_context=True)
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 = 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(ctx.prefix, ctx.prefix)
await self.bot.send_message(ctx.message.author, 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 self.bot.send_message(ctx.message.author, msg)
return
# We are the creator - let's check the number of bots
if setting == None:
# Output idle kick status
if userGame['Timeout']:
await self.bot.send_message(ctx.message.channel, 'Idle kick is enabled.')
else:
await self.bot.send_message(ctx.message.channel, '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 self.bot.send_message(ctx.message.channel, msg)
@commands.command()
async def cahcredits(self):
"""Code credits."""
message = await self._credit()
await self.bot.say(message)
async def _credit(self):
message = "```This cog is made possible by CorpBot.\n"
message+= "Please visit https://github.com/corpnewt/CorpBot.py for more information.```"
return message
def setup(bot):
bot.add_cog(CardsAgainstHumanity(bot))