import os # OS Locations import yaml # YAML parser for Bot config files import asyncio # Discord Py Dependency import discord # Main Lib from discord.ext import commands # Commands module from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library from discord_slash.utils.manage_commands import create_choice, create_option, create_permission # Slash Command features from discord_slash.model import SlashCommandPermissionType from bot import configFile, yaml_load, yaml_dump, lookupFile, dataFile, gmFile, categoriesFile ##### Player Add, Remove, and Leave Commands class PlayerCommands(commands.Cog, name='Player Commands'): def __init__(self, client): self.client = client conf = yaml_load(configFile) lookup = yaml_load(lookupFile) data = yaml_load(dataFile) gms = yaml_load(gmFile) categories = yaml_load(categoriesFile) guild_ids= [ int(x) for x in list(lookup)] @cog_ext.cog_subcommand( base='player', name='add', description='Add a player to a game.', base_description='Commands to manage players in a game.', base_default_permission=True, guild_ids = guild_ids, options = [ create_option( name='player', description='The player you want to add to the game.', option_type=6, required=True ), create_option( name='game', description='The role of the game you want to add the player to.', option_type=8, required=True ) ] ) async def _player_add( self, ctx:SlashContext, player:discord.User, game:discord.Role ): await ctx.channel.trigger_typing() conf = yaml_load(configFile) lookup = yaml_load(lookupFile) data = yaml_load(dataFile) gms = yaml_load(gmFile) guildStr = str(ctx.guild.id) rStr = str(game.id) if rStr not in lookup[guildStr]: await ctx.send(f'```Error: This is not a valid game role. Please mention a role that is associated with a game.```',hidden=True) return if not (set(ctx.author.roles) & set([ctx.guild.get_role(x) for x in conf[str(ctx.guild.id)]['roles']['admin']]) or ctx.author == ctx.guild.owner): if ctx.author.id != lookup[guildStr][rStr]['gm']: await ctx.send(f'```Error: You are not authorised to issue this command. A player may only be added to a game by the GM or by an administrator.```',hidden=True) return if game in player.roles: await ctx.send(f'```Error: Player `{player.display_name}` is already in the game {lookup[guildStr][rStr]["game_title"]}.```',hidden=True) return await player.add_roles(game, reason=f'`/player add` command issued by {ctx.author.display_name}`.') t = lookup[guildStr][rStr]['time'] if type(data[guildStr][t][rStr]['current_players']) is not int: data[guildStr][t][rStr]['current_players'] = 1 else: data[guildStr][t][rStr]['current_players'] += 1 hm = data[guildStr][t][rStr]['header_message'] tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['text_channel'],ctx.guild.channels) if tc is not None: p = await tc.pins() if p: header = discord.utils.find(lambda x: x.id == hm, p) if header is not None: text = header.content.split('\n') for line, item in enumerate(text): if 'Current Players: ' in item: text[line] = f'Current Players: {str(data[guildStr][t][rStr]["current_players"])}' break await header.edit(content='\n'.join(text)) else: tPos = len(ctx.guild.channels) cat = discord.utils.find(lambda x: x.id==lookup[guildStr][rStr]['category'], ctx.guild.categories) if cat is not None: for t in cat.text_channels: if t.position <= tPos: tc = t tPos = t.position await tc.send(f'```Player {player.display_name} has been added to the game by `{ctx.author.display_name}`.```\n{player.mention} | {game.mention}') if 'mod' in conf[guildStr]['channels'] and 'committee' in conf[guildStr]['roles']: c = discord.utils.find(lambda x: x.id == conf[guildStr]['channels']['mod'], ctx.guild.channels) r = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['committee'], ctx.guild.roles) await c.send(f'```Player `{player.display_name}` has been added to the game `{lookup[guildStr][rStr]["game_title"]}` by `{ctx.author.display_name}` via the `/player add` command.```') yaml_dump(data,dataFile) await ctx.send(content=f'```Player `{player.display_name}` has been added to the game `{lookup[guildStr][rStr]["game_title"]}`.```', hidden=True) @cog_ext.cog_subcommand( base='player', name='remove', description='Remove a player from a game.', # base_description='Commands to manage players in a game.', base_default_permission=True, guild_ids = guild_ids, options = [ create_option( name='player', description='The player you want to remove from the game.', option_type=6, required=True ) ] ) async def _player_remove( self, ctx:SlashContext, player:discord.User ): await ctx.channel.trigger_typing() conf = yaml_load(configFile) lookup = yaml_load(lookupFile) data = yaml_load(dataFile) gms = yaml_load(gmFile) categories = yaml_load(categoriesFile) guildStr = str(ctx.guild.id) if str(ctx.channel.category.id) not in categories[guildStr]: await ctx.send(f'```Error: This command can only be issued in a text channel associated with a game.```', hidden=True) return game = discord.utils.find(lambda x: x.id == categories[guildStr][str(ctx.channel.category.id)], ctx.guild.roles) rStr = str(game.id) if not (set(ctx.author.roles) & set([ctx.guild.get_role(x) for x in conf[str(ctx.guild.id)]['roles']['admin']]) or ctx.author == ctx.guild.owner): if ctx.author.id != lookup[guildStr][rStr]['gm']: await ctx.send(f'```Error: You are not authorised to issue this command. A player may only be added to a game by the GM or by an administrator.```',hidden=True) return if game not in player.roles: await ctx.send(f'```Error: Player `{player.display_name}` is not in the game {lookup[guildStr][rStr]["game_title"]}.```',hidden=True) return await player.remove_roles(game, reason=f'`/player remove` command issued by {ctx.author.display_name}`.') t = lookup[guildStr][rStr]['time'] if data[guildStr][t][rStr]['current_players'] <= 1: data[guildStr][t][rStr]['current_players'] = 0 else: data[guildStr][t][rStr]['current_players'] -= 1 hm = data[guildStr][t][rStr]['header_message'] tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['text_channel'],ctx.guild.channels) if tc is not None: p = await tc.pins() if p: header = discord.utils.find(lambda x: x.id == hm, p) if header is not None: text = header.content.split('\n') for line, item in enumerate(text): if 'Current Players: ' in item: text[line] = f'Current Players: {str(data[guildStr][t][rStr]["current_players"]) if data[guildStr][t][rStr]["current_players"] is not None else str(0)}' break await header.edit(content='\n'.join(text)) else: tPos = len(ctx.guild.channels) cat = ctx.channel.category for t in cat.text_channels: if t.position <= tPos: tc = t tPos = t.position await tc.send(f'```Player {player.display_name} has been removed from the game by `{ctx.author.display_name}`.```\n{game.mention}') if 'mod' in conf[guildStr]['channels'] and 'committee' in conf[guildStr]['roles']: c = discord.utils.find(lambda x: x.id == conf[guildStr]['channels']['mod'], ctx.guild.channels) r = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['committee'], ctx.guild.roles) await c.send(f'```Player `{player.display_name}` has been removed from the game `{lookup[guildStr][rStr]["game_title"]}` by `{ctx.author.display_name}` via the `/player remove` command.```') yaml_dump(data,dataFile) await ctx.send(content=f'```Player `{player.display_name}` has been removed from the game `{lookup[guildStr][rStr]["game_title"]}`.```', hidden=True) @cog_ext.cog_subcommand( base='player', name='leave', description='Leave a game.', # base_description='Commands to manage players in a game.', base_default_permission=True, guild_ids = guild_ids ) async def _player_leave( self, ctx:SlashContext ): await ctx.channel.trigger_typing() conf = yaml_load(configFile) lookup = yaml_load(lookupFile) data = yaml_load(dataFile) gms = yaml_load(gmFile) categories = yaml_load(categoriesFile) guildStr = str(ctx.guild.id) player = ctx.author if str(ctx.channel.category.id) not in categories[guildStr]: await ctx.send(f'```Error: This command can only be issued in a text channel associated with the game you are trying to leave.```', hidden=True) return game = discord.utils.find(lambda x: x.id == categories[guildStr][str(ctx.channel.category.id)], ctx.guild.roles) rStr = str(game.id) if game not in player.roles: await ctx.send(f'```Error: You are not in the game {lookup[guildStr][rStr]["game_title"]}.```',hidden=True) return await player.remove_roles(game, reason=f'`/player leave` command issued by {ctx.author.display_name}`.') t = lookup[guildStr][rStr]['time'] if data[guildStr][t][rStr]['current_players'] <= 1: data[guildStr][t][rStr]['current_players'] = None else: data[guildStr][t][rStr]['current_players'] -= 1 hm = data[guildStr][t][rStr]['header_message'] tc = discord.utils.find(lambda x: x.id == lookup[guildStr][rStr]['text_channel'],ctx.guild.channels) if tc is not None: p = await tc.pins() if p: header = discord.utils.find(lambda x: x.id == hm, p) if header is not None: text = header.content.split('\n') for line, item in enumerate(text): if 'Current Players: ' in item: text[line] = f'Current Players: {str(data[guildStr][t][rStr]["current_players"]) if data[guildStr][t][rStr]["current_players"] is not None else str(0)}' break await header.edit(content='\n'.join(text)) else: tPos = len(ctx.guild.channels) cat = ctx.channel.category for t in cat.text_channels: if t.position <= tPos: tc = t tPos = t.position await tc.send(f'```Player `{player.display_name}` has left the game.```\n{game.mention}') if 'mod' in conf[guildStr]['channels'] and 'committee' in conf[guildStr]['roles']: c = discord.utils.find(lambda x: x.id == conf[guildStr]['channels']['mod'], ctx.guild.channels) r = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['committee'], ctx.guild.roles) await c.send(f'```Player `{player.display_name}` has left the game `{lookup[guildStr][rStr]["game_title"]}` via the `/player leave` command.```') yaml_dump(data,dataFile) await ctx.send(content=f'```You have left the game `{lookup[guildStr][rStr]["game_title"]}`.```', hidden=True) def setup(client): client.add_cog(PlayerCommands(client))