Files
aikaterna-cogs/cah/cah.py

1691 lines
72 KiB
Python

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('<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 = 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))