import os import pymongo import discord from discord.ext import commands from bot import dbClient, p, state, gameTimes, gameTime, timeSlotList, dbFindTimeslot, dbLookupRole, in_game_channel # Lookup GMs def gmLookup(guild, member): gamesList = [] db = dbClient[str(guild.id)] try: for c in db.list_collection_names(): ret = db[c].find({'gm':member.id}) for e in ret: gamesList.append(guild.get_role(e['role'])) except: for cat in guild.categories: if cat.name.split(': ',maxsplit=1)[0] in timeSlotList(): for p in cat.overwrites: if cat.overwrites[member].manage_channels: for r in guild.roles: if r.name == cat.name: gamesList.append(r) break break finally: return gamesList # Check if User is a GM def user_is_GM(ctx): if ctx.author.guild_permissions.administrator: return True if len(gmLookup(ctx.guild,ctx.author)) > 0: return True # Check if User is a Player def user_is_Player(ctx): gamesList = [] db = dbClient[str(ctx.guild.id)] try: for c in db.list_collection_names(): ret = db[c].find({}) for e in ret: gamesList.append(ctx.guild.get_role(e['role'])) except: for r in ctx.guild.roles: if r.name.split(': ',maxsplit = 1)[0] in timeSlotList(): gamesList.append(r) if set(gamesList) & set(ctx.author.roles): return True raise commands.CommandError('Error: You are not currently playing in any game.') class GameManagement(commands.Cog, name='Game Management Commands'): def __init__(self, client): self.client = client # GM Kick Command @commands.command(name='kickplayer', aliases=['kick','removeplayer','dropplayer','drop', 'remove'],description='This removes a player from your game. Can only be invoked by the GM or a server admin. The syntax is `kickplayer {@Player}`. **This command must be called inside the text channel of the game you are kicking the player from.**. *The action gets logged with the Committee so we can keep track of who is in wose game.*') @commands.check(user_is_GM) @commands.check(in_game_channel) async def kickPlayer(self, ctx, arg): if not (arg.startswith('<@') and not (arg.startswith('<@&'))): raise commands.CommandError('Invalid argument. The second parameter must @ the Player.') if not ctx.author.permissions_in(ctx.channel.category).manage_channels: raise commands.CommandError('You are not authorised to use this command here as you are not the GM.') await ctx.message.delete() await ctx.channel.trigger_typing() permissions = ctx.channel.category.overwrites for p in permissions: if isinstance(p,discord.Role) and p.name == ctx.channel.category.name: break u = await ctx.guild.fetch_member(int(arg.replace('<@', '').replace('>', '').replace('!', ''))) await u.remove_roles(p) isPlayer = False for playerRoles in u.roles: if playerRoles.name.split(': ',maxsplit=1)[0] in timeSlotList(): isPlayer = True break if not isPlayer: for r in ctx.guild.roles: if r.name == 'Players': break if r.name == 'Players': await u.remove_roles(r) for cr in ctx.guild.roles: if cr.name == 'Committee': break await ctx.channel.send(f'{u.mention} has been kicked from the game. This has been logged with the {cr.mention}.') for tc in ctx.guild.text_channels: if tc.name.split('-',maxsplit=1)[1] == 'moderator-logs': break await tc.send(f'Hey {cr.mention}, {u.mention} has been kicked from the {p.mention} game by GM {ctx.author.mention}.') @kickPlayer.error async def clear_kick_error(self, ctx, error): if isinstance(error, commands.CheckFailure): await ctx.channel.send('You are not authorised to use this command as you are not a GM.') raise error # GM Add Command @commands.command(name='addplayer', aliases=['add'],description='This command adds a player to your game. Can only be invoked by the GM for the game. The syntax is `addplayer {@Player} {@Game Role}`. As you cannot @-mention someone who cannot already see your channel, you are **not restricted** to use this command in a text channel belonging to your game. *The action gets logged with the Committee so we can keep track of who is in wose game.*') @commands.check(user_is_GM) async def addPlayer(self, ctx, arg1, arg2): if not (arg1.startswith('<@') and not (arg1.startswith('<@&'))): raise commands.CommandError('Invalid argument. The first parameter must @ the Player.') if not arg2.startswith('<@&'): raise commands.CommandError('Invalid argument. The second parameter must @ the game role.') r = ctx.guild.get_role(int(arg2[3:-1])) if r.name.split(': ',maxsplit=1)[0] not in timeSlotList(): raise commands.CommandError('Error: the role is not a valid game role.') cat = dbLookupRole(ctx.guild,r) if not ctx.author.permissions_in(cat).manage_channels: raise commands.CommandError('You are not authorised to use this command as you are not the GM for the game.') await ctx.message.delete() await ctx.channel.trigger_typing() u = await ctx.guild.fetch_member(int(arg1.replace('<@', '').replace('>', '').replace('!', ''))) for rl in ctx.guild.roles: if rl.name == 'Players': break await u.add_roles(r,rl) tPos = len(ctx.guild.channels) tFirst = None for t in cat.text_channels: if t.position <= tPos: tFirst = t tPos = t.position for cr in ctx.guild.roles: if cr.name == 'Committee': break for tc in ctx.guild.text_channels: if tc.name.split('-',maxsplit=1)[1] == 'moderator-logs': break await tFirst.send(f'{u.mention} has joined the game. Welcome! This has been logged with the {cr.mention}.') await ctx.channel.send(f'{u.mention} has been added to the game {r.mention}.') await tc.send(f'Hey {cr.mention}, {u.mention} was added to the {r.mention} game by {ctx.author.mention}.') @addPlayer.error async def clear_add_error(self, ctx, error): if isinstance(error, commands.CheckFailure): await ctx.channel.send('You are not authorised to use this command as you are not a GM.') raise error # Leave Game Command @commands.command(name='leave',aliases=['leavegame','quit','quitgame','dropout'],description='This command is to leave the game you are in. **It must be invoked in the text channel of the game you are in.** *The action gets logged with the Committee so we can keep track of who is in wose game.*') @commands.check(user_is_Player) @commands.check(in_game_channel) async def leaveGame(self, ctx): await ctx.message.delete() await ctx.channel.trigger_typing() permissions = ctx.channel.category.overwrites for p in permissions: if isinstance(p,discord.Role) and p.name == ctx.channel.category.name: break await ctx.author.remove_roles(p) isPlayer = False for playerRoles in ctx.author.roles: if playerRoles.name.split(': ',maxsplit=1)[0] in timeSlotList(): isPlayer = True break if not isPlayer: for r in ctx.guild.roles: if r.name == 'Players': break if r.name == 'Players': await ctx.author.remove_roles(r) for cr in ctx.guild.roles: if cr.name == 'Committee': break await ctx.channel.send(f'{ctx.author.mention} has left the game. This has been logged with the {cr.mention}.') for tc in ctx.guild.text_channels: if tc.name.split('-',maxsplit=1)[1] == 'moderator-logs': break await tc.send(f'Hey {cr.mention}, {ctx.author.mention} has left the {p.mention} game by GM {ctx.author.mention}.') # Cog Setup Function def setup(client): client.add_cog(GameManagement(client))