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 discord_slash.client import SlashCommand import re from bot import configFile, yaml_load, yaml_dump, reloadCog, cogsDir, unloadCog, dataFile, lookupFile #### Game Role and Channel Management Commands class GameSetup(commands.Cog, name='Game Setup'): def __init__(self, client): self.client = client permissions={} guild_ids = list(set.union(set([int(guildKey) for guildKey in yaml_load(configFile) if len(yaml_load(configFile)[guildKey]['timeslots']) > 0]),set([int(guildKey) for guildKey in yaml_load(configFile) if type(yaml_load(configFile)[guildKey]['roles']['bot']) is int]))) permissions[guildID] = [] permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True)) for admin in conf[str(guildID)]['roles']['admin']: permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True)) @cog_ext.cog_subcommand( base='game', # subcommand_group='', name='create', description='Create a new game role and accompanying category, text, and voice channels.', base_description='Commands for setting up and removing games on the Guild.', base_default_permission=False, base_permissions=permissions, # subcommand_group_description='Adds a time slot available to the channel for games.', guild_ids=guild_ids, options=[ create_option( name='timeslot', description='The timeslot code for when the game will run.', option_type=3, required=True ), create_option( name='gm', description='The person who will be running the game.', option_type=6, required=True ), create_option( name='max_players', description='The maximum number of players the GM can take.', option_type=3, required=True ), create_option( name='min_players', description='The minimum number of players the GM can take.', option_type=3, required=False ), create_option( name='reserved_spaces', description='The number of spaces the GM is reserving in the game.', option_type=3, required=False ), create_option( name='game_title', description='What the game is called.', option_type=3, required=True ), create_option( name='system', description='What system the game is using.', option_type=3, required=False ), create_option( name='platform', description='What platform the game will be running on.', option_type=3, required=False ) ] ) async def _game_create( self, ctx:SlashContext, timeslot:str, gm:discord.Member, max_players:int, game_title:str, min_players:int=None, reserved_spaces:int=None, system:str=None, platform:str=None ): await ctx.channel.trigger_typing() conf = yaml_load(configFile) data = yaml_load(dataFile) lookup = yaml_load(lookupFile) guildStr = str(ctx.guild.id) time = re.sub(r"\W+",'', timeslot[:9].lower()) if 'roles' not in conf[guildStr]: conf[guildStr]['roles'] = {} if 'bot' not in conf[guildStr]['roles']: await ctx.send(f'```\`Bot` role for guild `{ctx.guild.name}` has not been defined. Cannot configure game.```') return if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {} if time not in conf[guildStr]['timeslots']: await ctx.send(f'```Time code `{timeslot}` is not recognised. Please enter a valid time code to register the game.```') return if guildStr not in data: data[guildStr] = {} if time not in data[guildStr]: data[guildStr][time] = [] r = await ctx.guild.create_role( name=f'{time.upper}: {game_title}', reason=f'/game create command issued by `{ctx.author.display_name}`', mentionable=True, permissions=discord.Permissions.none(), ) permissions = { ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False), r: discord.PermissionOverwrite(read_messages=True), ctx.guild.get_role(conf[guildStr]['roles']['bot']): discord.PermissionOverwrite(read_messages=True), gm: discord.PermissionOverwrite(read_messages=True, manage_messages=True, manage_channels=True, manage_permissions=True,priority_speaker=True,move_members=True,mute_members=True,deafen_members=True) } c = await ctx.guild.create_category( name=f'{time.upper}: {game_title}', overwrites=permissions, reason=f'/game create command issued by `{ctx.author.display_name}`' ) await c.create_voice_channel(name=f'voice: {game_title}', topic=f'Default voice channel for the game `{game_title}`` taking place at `{conf[guildStr]["timeslots"][time]}`, with GM `{gm.display_name}`.',reason=f'/game create command issued by `{ctx.author.display_name}`') t = await c.create_text_channel( name=f'text: {game_title}', topic=f'Default text channel for the game `{game_title}`` taking place at `{conf[guildStr]["timeslots"][time]}`, with GM `{gm.display_name}`.', reason=f'/game create command issued by `{ctx.author.display_name}`' ) await ctx.send(f'```Roles and channels for the game `{game_title}` have been created.```\n{r.mention}') output = f'```Hello {gm.display_name}! Yout game channels for `{game_title}` have been created.\nYou can ping your players or edit the game settings by interacting with the game role through the Bot commands. Have fun!```\n' output = ''.join([output,f'```Game Title: {game_title}\n']) output = ''.join([output,f'GM: {gm.display_name}\n']) output = ''.join([output,f'Time: {conf[guildStr]["timeslots"][time]}\n']) output = ''.join([output,f'System: {system}\n'if system is not None else '']) output = ''.join([output,f'Max Players: {max_players}\n']) output = ''.join([output,f'Min Players: {min_players}\n'if min_players is not None else '']) output = ''.join([output,f'Reserved Spaces: {reserved_spaces}\n' if reserved_spaces is not None else '']) output = ''.join([output,f'Platform: {platform}```' if platform is not None else '```']) o = await t.send(output) await o.pin(reason=f'/game create command issued by `{ctx.author.display_name}`') tDict = {} tDict['game_title'] = game_title tDict['gm'] = gm.id tDict['max_players'] = max_players tDict['min_players'] = min_players tDict['reserved_spaces'] = reserved_spaces tDict['system'] = system tDict['platform'] = platform tDict['role'] = r.id tDict['category'] = c.id data[guildStr][time].append(tDict) if guildStr not in lookup: lookup[guildStr] = {} lookup[guildStr][str(r.id)] = {} lookup[guildStr][str(r.id)]['category'] = c.id lookup[guildStr][str(r.id)]['gm'] = gm.id lookup[guildStr][str(r.id)]['time'] = time yaml_dump(data,dataFile) yaml_dump(lookup,lookupFile) ### Move delete, Modify, and Reset commands to a separate secondary cog to enable when games exist? @cog_ext.cog_subcommand( base='game', # subcommand_group='', name='delete', description='Deletes a game role and accompanying category, text, voice channels, and data.', # base_description='Commands for setting up and removing games on the Guild.', # base_default_permission=False, # base_permissions=permissions, # subcommand_group_description='Adds a time slot available to the channel for games.', guild_ids=guild_ids, options=[ create_option( name='game_role', description='The role representing the game you want to interact with.', option_type=8, required=True ) ] ) async def _game_delete(self, ctx:SlashContext, game_role:discord.Role): await ctx.channel.trigger_typing() conf = yaml_load(configFile) data = yaml_load(dataFile) lookup = yaml_load(lookupFile) guildStr = str(ctx.guild.id) if str(game_role.id) not in lookup[guildStr]: await ctx.send(f'```This is not a valid game role. Please mention a role that is associated with a game..```') return time = lookup[guildStr][str(game_role.id)]['time'] c = ctx.guild.get_channel(lookup[guildStr][str(game_role.id)]['category']) for g in list(data[guildStr][time]): if game_role.id in g.values(): data[guildStr][time].remove(g) break for t in ctx.guild.text_channels: if t.category == c: await t.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`') for v in ctx.guild.voice_channels: if v.category == c: await v.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`') await c.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`') lookup[guildStr].pop(str(game_role.id), None) await game_role.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`') yaml_dump(lookup, lookupFile) yaml_dump(data, dataFile) def setup(client): client.add_cog(GameSetup(client))