Finished writing Pitch command.
Needs further testing. Prepare to write member verification and event listeners next.
This commit is contained in:
		
							
								
								
									
										23
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								TODO.md
									
									
									
									
									
								
							@@ -10,7 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- [x] Setup minimally functioning configs of guild on startup
 | 
					- [x] Setup minimally functioning configs of guild on startup
 | 
				
			||||||
- [x] Synchronise core configuration `/commands` on startup
 | 
					- [x] Synchronise core configuration `/commands` on startup
 | 
				
			||||||
- [ ] ~~Synchronise secondary `/commands` on complete configuration **(see below)**~~
 | 
					- [ ] ~~Synchronise secondary `/commands` on complete configuration~~ ``(see below)``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Bot Functionality and Processes
 | 
					## Bot Functionality and Processes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
- [x] Infer Permissions from Config
 | 
					- [x] Infer Permissions from Config
 | 
				
			||||||
- [x] Dynamic Command Prefixes
 | 
					- [x] Dynamic Command Prefixes
 | 
				
			||||||
- [ ] Infer current games from Server Structure
 | 
					- [ ] Infer current games from Server Structure
 | 
				
			||||||
**Create a separate cog to do this instead of having a migrate command, install the cog temporarily and remove the cog once migration is done.**
 | 
					`Create a separate cog to do this instead of having a migrate command, install the cog temporarily and remove the cog once migration is done.`
 | 
				
			||||||
- [ ] Re-enable logging
 | 
					- [ ] Re-enable logging
 | 
				
			||||||
- [x] Delete Dev/Test Functions
 | 
					- [x] Delete Dev/Test Functions
 | 
				
			||||||
- [x] Error handlers
 | 
					- [x] Error handlers
 | 
				
			||||||
@@ -31,8 +31,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> - [x] Add Config key for Help Channel
 | 
					> - [x] Add Config key for Help Channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] Slash Command Buttons or
 | 
					- [ ] ~~Slash Command Buttons or~~ `This kind of got subsumed into other features.`
 | 
				
			||||||
- [ ] Reaction listener selectors
 | 
					- [ ] ~~Reaction listener selectors~~ `So did this.`
 | 
				
			||||||
- [ ] Member Verification
 | 
					- [ ] Member Verification
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> - [x] Add Config key membership signup channels
 | 
					> - [x] Add Config key membership signup channels
 | 
				
			||||||
@@ -45,7 +45,7 @@
 | 
				
			|||||||
> - [ ] Message Receive Listener
 | 
					> - [ ] Message Receive Listener
 | 
				
			||||||
> - [ ] Membership Validation Listener
 | 
					> - [ ] Membership Validation Listener
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] Re-synchronise commands after any relevant config changes **(see above)**
 | 
					- [ ] Re-synchronise commands after any relevant config changes `(See from above)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> - [ ] Role Delete (member, admin, game)
 | 
					> - [ ] Role Delete (member, admin, game)
 | 
				
			||||||
> - [ ] Channel delete (notifications, logs, game text channel)
 | 
					> - [ ] Channel delete (notifications, logs, game text channel)
 | 
				
			||||||
@@ -93,25 +93,26 @@ Do the opposite: block deleting timeslots with existing games.
 | 
				
			|||||||
- [x] Set up command permissions
 | 
					- [x] Set up command permissions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> - [x] Slash Commands
 | 
					> - [x] Slash Commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
>> - [x] Admin Commands
 | 
					>> - [x] Admin Commands
 | 
				
			||||||
>> - [x] Game Management Commands
 | 
					>> - [x] Game Management Commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> - [x] Native Bot Commands
 | 
					> - [x] Native Bot Commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] Migrate existing bot commands
 | 
					- [x] Migrate existing bot commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> - [x] setupgame
 | 
					> - [x] setupgame
 | 
				
			||||||
> - [x] ~~definebotrole~~ config
 | 
					> - [x] ~~definebotrole~~ config
 | 
				
			||||||
> - [x] deletegame
 | 
					> - [x] deletegame
 | 
				
			||||||
> - [x] ~~reset~~ purge
 | 
					> - [x] ~~reset~~ purge
 | 
				
			||||||
> - [ ] ~~migrate~~ **See above**
 | 
					> - [ ] ~~migrate~~ `See above`
 | 
				
			||||||
> - [x] ~~kickplayer~~ `/player remove`
 | 
					> - [x] ~~kickplayer~~ `/player remove`
 | 
				
			||||||
> - [x] ~~addplayer~~ `/player add`
 | 
					> - [x] ~~addplayer~~ `/player add`
 | 
				
			||||||
> - [x] ~~leavegame~~ `/player leave`
 | 
					> - [x] ~~leavegame~~ `/player leave`
 | 
				
			||||||
> - [ ] Pitch command and sub-commands
 | 
					> - [x] Pitch command and sub-commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> > - [ ] run
 | 
					> > - [ ] ~~run~~ `Combined both sub-commands into single command and prompt response.`
 | 
				
			||||||
> > - [ ] clear
 | 
					> > - [ ] ~~clear~~ 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Misc
 | 
					## Misc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,4 +123,4 @@ Do the opposite: block deleting timeslots with existing games.
 | 
				
			|||||||
> - [ ] COMMANDS.md
 | 
					> - [ ] COMMANDS.md
 | 
				
			||||||
> - [ ] resources.md
 | 
					> - [ ] resources.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] Make sure to document **not using discord_components and staying with discord-py-slash-commands library alone**.
 | 
					- [ ] Make sure to document `not using discord_components and staying with discord-py-slash-commands library alone`.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								app/bot.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								app/bot.py
									
									
									
									
									
								
							@@ -54,6 +54,9 @@ categoriesFile = os.getenv('CATEGORIES') if os.getenv('CATEGORIES').endswith('.y
 | 
				
			|||||||
if not os.path.exists(categoriesFile):
 | 
					if not os.path.exists(categoriesFile):
 | 
				
			||||||
	yaml_dump({},categoriesFile)
 | 
						yaml_dump({},categoriesFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					l = [dataFile, lookupFile, gmFile, categoriesFile]
 | 
				
			||||||
 | 
					if len(set(l)) != len(l): raise Exception('Config Error: there is a clash between two file names.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Locate Cogs Directory
 | 
					# Locate Cogs Directory
 | 
				
			||||||
cogsDir = 'cogs'
 | 
					cogsDir = 'cogs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -267,14 +270,15 @@ loadCogs('events')
 | 
				
			|||||||
loadCogs('botcommands')
 | 
					loadCogs('botcommands')
 | 
				
			||||||
loadCogs('slashcommands')
 | 
					loadCogs('slashcommands')
 | 
				
			||||||
if yaml_load(configFile):
 | 
					if yaml_load(configFile):
 | 
				
			||||||
	if any([len(yaml_load(configFile)[x]['timeslots']) > 0 for x in yaml_load(configFile)]):
 | 
						if any([yaml_load(configFile)[x]['timeslots'] for x in yaml_load(configFile)]):
 | 
				
			||||||
		loadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
							loadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
				
			||||||
		if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
							if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
				
			||||||
			loadCog(f'./{cogsDir}/slashcommands/secondary/game_setup.py')
 | 
								loadCog(f'./{cogsDir}/slashcommands/secondary/game_create.py')
 | 
				
			||||||
			if yaml_load(lookupFile):
 | 
								if yaml_load(lookupFile):
 | 
				
			||||||
				if any([len(x) > 0 for x in yaml_load(lookupFile).values()]):
 | 
									if any([x for x in yaml_load(lookupFile).values()]):
 | 
				
			||||||
					loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
										loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
					loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
										loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
										loadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
	if any([len(yaml_load(configFile)[x]['membership']) > 0 for x in yaml_load(configFile)]):
 | 
						if any([len(yaml_load(configFile)[x]['membership']) > 0 for x in yaml_load(configFile)]):
 | 
				
			||||||
		loadCog(f'./{cogsDir}/slashcommands/secondary/edit_membership.py')
 | 
							loadCog(f'./{cogsDir}/slashcommands/secondary/edit_membership.py')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,7 @@ class Configuration(commands.Cog, name='Configuration Commands'):
 | 
				
			|||||||
	for gStr in conf:
 | 
						for gStr in conf:
 | 
				
			||||||
		permissions[int(gStr)] = []
 | 
							permissions[int(gStr)] = []
 | 
				
			||||||
		permissions[int(gStr)].append(create_permission(id=conf[gStr]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
							permissions[int(gStr)].append(create_permission(id=conf[gStr]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
				
			||||||
		for admin in conf[gStr]['roles']['admin']:
 | 
							for admin in conf[gStr]['roles']['admin']: permissions[int(gStr)].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
				
			||||||
			permissions[int(gStr)].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@cog_ext.cog_subcommand(
 | 
						@cog_ext.cog_subcommand(
 | 
				
			||||||
		base='config',
 | 
							base='config',
 | 
				
			||||||
@@ -110,13 +109,19 @@ class Configuration(commands.Cog, name='Configuration Commands'):
 | 
				
			|||||||
		if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
							if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
				
			||||||
			if any([yaml_load(configFile)[x]['timeslots'] for x in yaml_load(configFile)]):
 | 
								if any([yaml_load(configFile)[x]['timeslots'] for x in yaml_load(configFile)]):
 | 
				
			||||||
				flag = False
 | 
									flag = False
 | 
				
			||||||
				if self.client.get_cog('Game Setup') is None:
 | 
									if self.client.get_cog('Game Create') is None:
 | 
				
			||||||
					loadCog(f'./{cogsDir}/slashcommands/secondary/game_setup.py')
 | 
										loadCog(f'./{cogsDir}/slashcommands/secondary/game_create.py')
 | 
				
			||||||
					flag = True
 | 
										flag = True
 | 
				
			||||||
				if any([x for x in yaml_load(lookupFile).values()]):
 | 
									if any([x for x in yaml_load(lookupFile).values()]):
 | 
				
			||||||
					if self.client.get_cog('Game Management') is None:
 | 
										if self.client.get_cog('Game Management') is None:
 | 
				
			||||||
						loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
											loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
						flag = True
 | 
											flag = True
 | 
				
			||||||
 | 
										if self.client.get_cog('Player Commands') is None:
 | 
				
			||||||
 | 
											loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
											flag = True
 | 
				
			||||||
 | 
										if self.client.get_cog('Pitch') is None:
 | 
				
			||||||
 | 
											loadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
 | 
											flag = True
 | 
				
			||||||
			if flag: await self.client.slash.sync_all_commands()
 | 
								if flag: await self.client.slash.sync_all_commands()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@cog_ext.cog_subcommand(
 | 
						@cog_ext.cog_subcommand(
 | 
				
			||||||
@@ -281,14 +286,20 @@ class Configuration(commands.Cog, name='Configuration Commands'):
 | 
				
			|||||||
				loadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
									loadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
				
			||||||
				flag = True
 | 
									flag = True
 | 
				
			||||||
			if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
								if any(['bot' in yaml_load(configFile)[x]['roles'] for x in yaml_load(configFile)]):
 | 
				
			||||||
				if self.client.get_cog('Game Setup') is None:
 | 
									if self.client.get_cog('Game Create') is None:
 | 
				
			||||||
					loadCog(f'./{cogsDir}/slashcommands/secondary/game_setup.py')
 | 
										loadCog(f'./{cogsDir}/slashcommands/secondary/game_create.py')
 | 
				
			||||||
					Flag = True
 | 
										Flag = True
 | 
				
			||||||
				if yaml_load(lookupFile):
 | 
									if yaml_load(lookupFile):
 | 
				
			||||||
					if any([x for x in yaml_load(lookupFile).values()]):
 | 
										if any([x for x in yaml_load(lookupFile).values()]):
 | 
				
			||||||
						if self.client.get_cog('Game Management') is None:
 | 
											if self.client.get_cog('Game Management') is None:
 | 
				
			||||||
							loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
												loadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
							Flag = True
 | 
												Flag = True
 | 
				
			||||||
 | 
											if self.client.get_cog('Player Commands') is None:
 | 
				
			||||||
 | 
												loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
												Flag = True
 | 
				
			||||||
 | 
											if self.client.get_cog('Pitch') is None:
 | 
				
			||||||
 | 
												loadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
 | 
												Flag = True
 | 
				
			||||||
			if flag: await self.client.slash.sync_all_commands()
 | 
								if flag: await self.client.slash.sync_all_commands()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@cog_ext.cog_subcommand(
 | 
						@cog_ext.cog_subcommand(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ from bot import configFile, yaml_load, yaml_dump, cogsDir, unloadCog, dataFile,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#### Game Role and Channel Setup Command
 | 
					#### Game Role and Channel Setup Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GameSetup(commands.Cog, name='Game Setup'):
 | 
					class GameCreate(commands.Cog, name='Game Create'):
 | 
				
			||||||
	def __init__(self, client):
 | 
						def __init__(self, client):
 | 
				
			||||||
		self.client = client
 | 
							self.client = client
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -24,12 +24,10 @@ class GameSetup(commands.Cog, name='Game Setup'):
 | 
				
			|||||||
	for guildID in guild_ids:
 | 
						for guildID in guild_ids:
 | 
				
			||||||
		permissions[guildID] = []
 | 
							permissions[guildID] = []
 | 
				
			||||||
		permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
							permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
				
			||||||
		for admin in conf[str(guildID)]['roles']['admin']:
 | 
							for admin in conf[str(guildID)]['roles']['admin']: permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
				
			||||||
			permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
					 | 
				
			||||||
	permissions[guildID] = []
 | 
						permissions[guildID] = []
 | 
				
			||||||
	permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
						permissions[guildID].append(create_permission(id=conf[str(guildID)]['owner'],id_type=SlashCommandPermissionType.USER,permission=True))
 | 
				
			||||||
	for admin in conf[str(guildID)]['roles']['admin']:
 | 
						for admin in conf[str(guildID)]['roles']['admin']: permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
				
			||||||
		permissions[guildID].append(create_permission(id=admin,id_type=SlashCommandPermissionType.ROLE,permission=True))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@cog_ext.cog_subcommand(
 | 
						@cog_ext.cog_subcommand(
 | 
				
			||||||
		base='game',
 | 
							base='game',
 | 
				
			||||||
@@ -115,31 +113,29 @@ class GameSetup(commands.Cog, name='Game Setup'):
 | 
				
			|||||||
		if 'roles' not in conf[guildStr]:
 | 
							if 'roles' not in conf[guildStr]:
 | 
				
			||||||
			conf[guildStr]['roles'] = {}
 | 
								conf[guildStr]['roles'] = {}
 | 
				
			||||||
		if 'bot' not in 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.```',hidden=True)
 | 
								await ctx.send(f'```Error: `Bot` role for guild `{ctx.guild.name}` has not been defined. Cannot configure game.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if 'timeslots' not in conf[guildStr]:
 | 
							if 'timeslots' not in conf[guildStr]:
 | 
				
			||||||
			conf[guildStr]['timeslots'] = {}
 | 
								conf[guildStr]['timeslots'] = {}
 | 
				
			||||||
		if time not in 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. use `/config timeslots list` to get a list of valid time codes.```',hidden=True)
 | 
								await ctx.send(f'```Error: Time code `{timeslot}` is not recognised. Please enter a valid time code to register the game. use `/config timeslots list` to get a list of valid time codes.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if min_players and min_players > max_players:
 | 
							if min_players and min_players > max_players:
 | 
				
			||||||
			await ctx.send(f'```The minimum number of players cannot exceed the maximum number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: The minimum number of players cannot exceed the maximum number of players.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if current_players and current_players > max_players:
 | 
							if current_players and current_players > max_players:
 | 
				
			||||||
			await ctx.send(f'```The number of reserved spaces cannot exceed the maximum number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: The number of reserved spaces cannot exceed the maximum number of players.```',hidden=True)
 | 
				
			||||||
			return 
 | 
								return 
 | 
				
			||||||
		if any(x is not None and x < 0 for x in [min_players, max_players, current_players]):
 | 
							if any(x is not None and x < 0 for x in [min_players, max_players, current_players]):
 | 
				
			||||||
			await ctx.send(f'```You cannot enter negative integers for the number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: You cannot enter negative integers for the number of players.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if guildStr not in lookup:
 | 
							if guildStr not in lookup:
 | 
				
			||||||
			lookup[guildStr] = {}
 | 
								lookup[guildStr] = {}
 | 
				
			||||||
		if game_title in [x['game_title'] for x in lookup[str(ctx.guild.id)].values()] and time in [x['time'] for x in lookup[str(ctx.guild.id)].values()]:
 | 
							if game_title in [x['game_title'] for x in lookup[str(ctx.guild.id)].values()] and time in [x['time'] for x in lookup[str(ctx.guild.id)].values()]:
 | 
				
			||||||
			await ctx.send(f'```Game `{game_title}` has already been created for the time slot `{conf[guildStr]["timeslots"][time]}`. Please avoud duplicates, or use the `modify` sub-command to edit the existing game.```',hidden=True)
 | 
								await ctx.send(f'```Error: Game `{game_title}` has already been created for the time slot `{conf[guildStr]["timeslots"][time]}`. Please avoud duplicates, or use the `modify` sub-command to edit the existing game.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if guildStr not in data:
 | 
							if guildStr not in data: data[guildStr] = {}
 | 
				
			||||||
			data[guildStr] = {}
 | 
							if time not in data[guildStr]: data[guildStr][time] = {}
 | 
				
			||||||
		if time not in data[guildStr]:
 | 
					 | 
				
			||||||
			data[guildStr][time] = {}
 | 
					 | 
				
			||||||
		rExists, cExists = False, False
 | 
							rExists, cExists = False, False
 | 
				
			||||||
		r = discord.utils.get(ctx.guild.roles, name=f'{time.upper()}: {game_title}')
 | 
							r = discord.utils.get(ctx.guild.roles, name=f'{time.upper()}: {game_title}')
 | 
				
			||||||
		if not r:
 | 
							if not r:
 | 
				
			||||||
@@ -260,7 +256,7 @@ class GameSetup(commands.Cog, name='Game Setup'):
 | 
				
			|||||||
			'gm': gm.id,
 | 
								'gm': gm.id,
 | 
				
			||||||
			'max_players': max_players,
 | 
								'max_players': max_players,
 | 
				
			||||||
			'min_players': min_players,
 | 
								'min_players': min_players,
 | 
				
			||||||
			'current_players': current_players,
 | 
								'current_players': current_players if current_players is not None else 0,
 | 
				
			||||||
			'system': system,
 | 
								'system': system,
 | 
				
			||||||
			'platform': platform,
 | 
								'platform': platform,
 | 
				
			||||||
			'role': r.id,
 | 
								'role': r.id,
 | 
				
			||||||
@@ -294,7 +290,10 @@ class GameSetup(commands.Cog, name='Game Setup'):
 | 
				
			|||||||
			if self.client.get_cog('Player Commands') is None:
 | 
								if self.client.get_cog('Player Commands') is None:
 | 
				
			||||||
				loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
									loadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
				flag = True
 | 
									flag = True
 | 
				
			||||||
 | 
								if self.client.get_cog('Pitch') is None:
 | 
				
			||||||
 | 
									loadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
 | 
									flag = True
 | 
				
			||||||
			if flag: await self.client.slash.sync_all_commands()
 | 
								if flag: await self.client.slash.sync_all_commands()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup(client):
 | 
					def setup(client):
 | 
				
			||||||
	client.add_cog(GameSetup(client))
 | 
						client.add_cog(GameCreate(client))
 | 
				
			||||||
@@ -52,8 +52,14 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
		categories = yaml_load(categoriesFile)
 | 
							categories = yaml_load(categoriesFile)
 | 
				
			||||||
		guildStr = str(ctx.guild.id)
 | 
							guildStr = str(ctx.guild.id)
 | 
				
			||||||
		rStr = str(game_role.id)
 | 
							rStr = str(game_role.id)
 | 
				
			||||||
 | 
							if 'bot' not in conf[guildStr]['roles']:
 | 
				
			||||||
 | 
								await ctx.send(f'```Error: `Bot` role for guild `{ctx.guild.name}` has not been defined. Cannot configure game.```',hidden=True)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		if rStr not in lookup[guildStr]:
 | 
							if rStr 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.```', hidden=True)
 | 
								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 ctx.channel.category.id != lookup[guildStr][rStr]['category']:
 | 
				
			||||||
 | 
								await ctx.send(f'```Error: You must issue this command in a text channel associated with the game you are trying to delete.```', hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		game_title = lookup[guildStr][rStr]['game_title']
 | 
							game_title = lookup[guildStr][rStr]['game_title']
 | 
				
			||||||
		time = lookup[guildStr][rStr]['time']
 | 
							time = lookup[guildStr][rStr]['time']
 | 
				
			||||||
@@ -69,7 +75,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
			for v in ctx.guild.voice_channels:
 | 
								for v in ctx.guild.voice_channels:
 | 
				
			||||||
				if v.category == c:
 | 
									if v.category == c:
 | 
				
			||||||
					await v.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`')
 | 
										await v.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`')
 | 
				
			||||||
			del categories[guildStr][c.id]
 | 
								del categories[guildStr][str(c.id)]
 | 
				
			||||||
			await c.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(rStr, None)
 | 
							lookup[guildStr].pop(rStr, None)
 | 
				
			||||||
		gm_m = await ctx.guild.fetch_member(gm)
 | 
							gm_m = await ctx.guild.fetch_member(gm)
 | 
				
			||||||
@@ -78,11 +84,15 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
			output = ''.join([output,' All associated text, voice, and category channels have been deleted.'])
 | 
								output = ''.join([output,' All associated text, voice, and category channels have been deleted.'])
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			output = ''.join([output,' No associated text, voice, or category channels were found. Please delete them manually if they still persist.'])
 | 
								output = ''.join([output,' No associated text, voice, or category channels were found. Please delete them manually if they still persist.'])
 | 
				
			||||||
		await ctx.send(f'```{output}```',hidden=True)
 | 
							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)
 | 
				
			||||||
 | 
									await c.send(
 | 
				
			||||||
 | 
										content = f'```{output}```'
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
		await game_role.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`')
 | 
							await game_role.delete(reason=f'/game delete command issued by `{ctx.author.display_name}`')
 | 
				
			||||||
		gms[guildStr][str(gm)].remove(game_role.id)
 | 
							gms[guildStr][str(gm)].remove(game_role.id)
 | 
				
			||||||
		if not gms[guildStr][str(gm)]:
 | 
							if not gms[guildStr][str(gm)]: del gms[guildStr][str(gm)]
 | 
				
			||||||
			del gms[guildStr][str(gm)]
 | 
							if not data[guildStr][time]: del data[guildStr][time]
 | 
				
			||||||
		yaml_dump(lookup, lookupFile)
 | 
							yaml_dump(lookup, lookupFile)
 | 
				
			||||||
		yaml_dump(data, dataFile)
 | 
							yaml_dump(data, dataFile)
 | 
				
			||||||
		yaml_dump(gms, gmFile)
 | 
							yaml_dump(gms, gmFile)
 | 
				
			||||||
@@ -90,6 +100,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
		if not any([x for x in yaml_load(lookupFile).values()]):
 | 
							if not any([x for x in yaml_load(lookupFile).values()]):
 | 
				
			||||||
			unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
								unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
			if self.client.get_cog('Player Commands') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
								if self.client.get_cog('Player Commands') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
								if self.client.get_cog('Pitch') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
			await self.client.slash.sync_all_commands()
 | 
								await self.client.slash.sync_all_commands()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@cog_ext.cog_subcommand(
 | 
						@cog_ext.cog_subcommand(
 | 
				
			||||||
@@ -174,7 +185,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
	):
 | 
						):
 | 
				
			||||||
		await ctx.channel.trigger_typing()
 | 
							await ctx.channel.trigger_typing()
 | 
				
			||||||
		if all(x is None for x in [timeslot, gm, max_players, game_title, min_players, current_players, system, platform]):
 | 
							if all(x is None for x in [timeslot, gm, max_players, game_title, min_players, current_players, system, platform]):
 | 
				
			||||||
			await ctx.send(f'```No parameters have been entered to modify the game.```',hidden=True)
 | 
								await ctx.send(f'```Error: No parameters have been entered to modify the game.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		conf = yaml_load(configFile)
 | 
							conf = yaml_load(configFile)
 | 
				
			||||||
		data = yaml_load(dataFile)
 | 
							data = yaml_load(dataFile)
 | 
				
			||||||
@@ -194,20 +205,20 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
			data[guildStr][time] = {}
 | 
								data[guildStr][time] = {}
 | 
				
			||||||
		# Command Validation Checks
 | 
							# Command Validation Checks
 | 
				
			||||||
		if rStr not in lookup[guildStr]:
 | 
							if rStr 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.```',hidden=True)
 | 
								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
 | 
								return
 | 
				
			||||||
		if timeslot is not None:
 | 
							if timeslot is not None:
 | 
				
			||||||
			if time not in 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. use `/config timeslots list` to get a list of valid time codes.```',hidden=True)
 | 
									await ctx.send(f'```Error: Time code `{timeslot}` is not recognised. Please enter a valid time code to register the game. use `/config timeslots list` to get a list of valid time codes.```',hidden=True)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
		if any(x is not None and x < 0 for x in [min_players, max_players, current_players]):
 | 
							if any(x is not None and x < 0 for x in [min_players, max_players, current_players]):
 | 
				
			||||||
			await ctx.send(f'```You cannot enter negative integers for the number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: You cannot enter negative integers for the number of players.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if min_players and max_players and min_players > max_players:
 | 
							if min_players and max_players and min_players > max_players:
 | 
				
			||||||
			await ctx.send(f'```The minimum number of players cannot exceed the maximum number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: The minimum number of players cannot exceed the maximum number of players.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if current_players and max_players and current_players > max_players:
 | 
							if current_players and max_players and current_players > max_players:
 | 
				
			||||||
			await ctx.send(f'```The number of reserved spaces cannot exceed the maximum number of players.```',hidden=True)
 | 
								await ctx.send(f'```Error: The number of reserved spaces cannot exceed the maximum number of players.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Infer Old Data
 | 
							# Infer Old Data
 | 
				
			||||||
@@ -223,7 +234,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
				del data[guildStr][old_time]
 | 
									del data[guildStr][old_time]
 | 
				
			||||||
		if game_title and game_title != old_data['game_title']:
 | 
							if game_title and game_title != old_data['game_title']:
 | 
				
			||||||
			if game_title in [x['game_title'] for x in lookup[str(ctx.guild.id)].values()] and time in [x['time'] for x in lookup[str(ctx.guild.id)].values()]:
 | 
								if game_title in [x['game_title'] for x in lookup[str(ctx.guild.id)].values()] and time in [x['time'] for x in lookup[str(ctx.guild.id)].values()]:
 | 
				
			||||||
				await ctx.send(f'```The target game `{game_title}` has already been created for the time slot `{conf[guildStr]["timeslots"][time]}`. Please avoud duplicates, or use the `modify` sub-command to edit the existing game.```',hidden=True)
 | 
									await ctx.send(f'```Error: The target game `{game_title}` has already been created for the time slot `{conf[guildStr]["timeslots"][time]}`. Please avoud duplicates, or use the `modify` sub-command to edit the existing game.```',hidden=True)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			result = ''.join([result,f"The game's title has been updated to {game_title}\n"])
 | 
								result = ''.join([result,f"The game's title has been updated to {game_title}\n"])
 | 
				
			||||||
		game_title = old_data['game_title'] if not game_title else game_title
 | 
							game_title = old_data['game_title'] if not game_title else game_title
 | 
				
			||||||
@@ -233,6 +244,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
		# Update Role
 | 
							# Update Role
 | 
				
			||||||
		await r.edit(
 | 
							await r.edit(
 | 
				
			||||||
			mentionable=True,
 | 
								mentionable=True,
 | 
				
			||||||
 | 
								name=f'{time.upper()}: {game_title}',
 | 
				
			||||||
			permissions=discord.Permissions.none(),
 | 
								permissions=discord.Permissions.none(),
 | 
				
			||||||
			reason=f'/game modify command issued by `{ctx.author.display_name}`',
 | 
								reason=f'/game modify command issued by `{ctx.author.display_name}`',
 | 
				
			||||||
			colour=discord.Colour.green()
 | 
								colour=discord.Colour.green()
 | 
				
			||||||
@@ -288,6 +300,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
		else:
 | 
							else:
 | 
				
			||||||
			cExists= True
 | 
								cExists= True
 | 
				
			||||||
			await c.edit(
 | 
								await c.edit(
 | 
				
			||||||
 | 
									name=f'{time.upper()}: {game_title}',
 | 
				
			||||||
				overwrites=permissions,
 | 
									overwrites=permissions,
 | 
				
			||||||
				reason=f'/game modify command issued by `{ctx.author.display_name}`',
 | 
									reason=f'/game modify command issued by `{ctx.author.display_name}`',
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
@@ -416,10 +429,10 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
				del lookup[guildStr][str(r.id)]
 | 
									del lookup[guildStr][str(r.id)]
 | 
				
			||||||
			del data[guildStr][timeslot]
 | 
								del data[guildStr][timeslot]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if 'timeslots' not in conf[guildStr]:
 | 
							if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {}
 | 
				
			||||||
			conf[guildStr]['timeslots'] = {}
 | 
							tsDict = {k: conf[guildStr]['timeslots'][k] for k in data[guildStr] if data[guildStr][k]}
 | 
				
			||||||
		tsDict = {k: conf[guildStr]['timeslots'][k] for k in  conf[guildStr]['timeslots'] if data[guildStr][k]}
 | 
							optionsList = [create_select_option(label=tsDict[x], value=x, description=x) for x in tsDict]
 | 
				
			||||||
		optionsList = [create_select_option(label=tsDict[x], value=x, description=x) for x in tsDict].insert(0, create_select_option(label='All Timeslots', value='--all', description='--all'))
 | 
							optionsList.insert(0, create_select_option(label='All Timeslots', value='--all', description='--all'))
 | 
				
			||||||
		try:
 | 
							try:
 | 
				
			||||||
			m = await ctx.send(
 | 
								m = await ctx.send(
 | 
				
			||||||
				content='```Select which time slot for which you would like to purge all games.```',
 | 
									content='```Select which time slot for which you would like to purge all games.```',
 | 
				
			||||||
@@ -448,7 +461,7 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		if timeslot == '--all':
 | 
							if timeslot == '--all':
 | 
				
			||||||
			m = await ctx.send(
 | 
								m = await ctx.send(
 | 
				
			||||||
				content=f'```You are attempting to purge games for all channels. This will delete every game currently running for guild {ctx.guild.name}. Are you sure?```',
 | 
									content=f'```You are attempting to purge games for all time slots. This will delete every game currently running for guild {ctx.guild.name}. Are you sure?```',
 | 
				
			||||||
				delete_after=5,
 | 
									delete_after=5,
 | 
				
			||||||
				components=[
 | 
									components=[
 | 
				
			||||||
					create_actionrow(
 | 
										create_actionrow(
 | 
				
			||||||
@@ -474,23 +487,68 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
				else:
 | 
									else:
 | 
				
			||||||
					break
 | 
										break
 | 
				
			||||||
			await m.delete()
 | 
								await m.delete()
 | 
				
			||||||
			if select_ctx.custom_id == 'purge_no':
 | 
								if button_ctx.custom_id == 'purge_no':
 | 
				
			||||||
				await ctx.send(f'```The action `/game purge --all` has been aborted.```',hidden=True)
 | 
									await ctx.send(f'```The action `/game purge --all` has been aborted.```',hidden=True)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			await ctx.channel.trigger_typing()
 | 
								await ctx.channel.trigger_typing()
 | 
				
			||||||
			for t in data[guildStr]:
 | 
								ctx_id = ctx.channel.id
 | 
				
			||||||
				await purgeGames(ctx=ctx, timeslot=t)
 | 
								for t in list(data[guildStr]): await purgeGames(ctx=ctx, timeslot=t)
 | 
				
			||||||
 | 
								if discord.utils.find(lambda x: x.id == ctx_id, ctx.guild.text_channels) is not None:
 | 
				
			||||||
				await ctx.send(
 | 
									await ctx.send(
 | 
				
			||||||
					content = '```All games for all time slots have been purged.```',
 | 
										content = '```All games for all time slots have been purged.```',
 | 
				
			||||||
					hidden=True
 | 
										hidden=True
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
			else:
 | 
								else:
 | 
				
			||||||
 | 
									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)
 | 
				
			||||||
 | 
										await c.send(
 | 
				
			||||||
 | 
											content = '```All games for all time slots have been purged.```'
 | 
				
			||||||
 | 
										)
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								m = await ctx.send(
 | 
				
			||||||
 | 
									content=f'```You are attempting to purge games for `{conf[guildStr]["timeslots"][timeslot]}` for guild {ctx.guild.name}. Are you sure?```',
 | 
				
			||||||
 | 
									delete_after=5,
 | 
				
			||||||
 | 
									components=[
 | 
				
			||||||
 | 
										create_actionrow(
 | 
				
			||||||
 | 
											create_button(
 | 
				
			||||||
 | 
												style=ButtonStyle.green,
 | 
				
			||||||
 | 
												label='Yes',
 | 
				
			||||||
 | 
												emoji='👍',
 | 
				
			||||||
 | 
												custom_id='purge_yes',
 | 
				
			||||||
 | 
											),
 | 
				
			||||||
 | 
											create_button(
 | 
				
			||||||
 | 
												style=ButtonStyle.red,
 | 
				
			||||||
 | 
												label='No',
 | 
				
			||||||
 | 
												emoji='👎',
 | 
				
			||||||
 | 
												custom_id='purge_no',
 | 
				
			||||||
 | 
											)
 | 
				
			||||||
 | 
										)
 | 
				
			||||||
 | 
									]
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								while True:
 | 
				
			||||||
 | 
									button_ctx = await wait_for_component(self.client, messages=m, timeout=5)
 | 
				
			||||||
 | 
									if button_ctx.author != ctx.author:
 | 
				
			||||||
 | 
										await button_ctx.send(f'```Invalid response: you are not the person who issued the command.```', hidden=True)
 | 
				
			||||||
 | 
									else:
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
								await m.delete()
 | 
				
			||||||
 | 
								if button_ctx.custom_id == 'purge_no':
 | 
				
			||||||
 | 
									await ctx.send(f'```The action `/game purge {timeslot}` has been aborted.```',hidden=True)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
			await ctx.channel.trigger_typing()
 | 
								await ctx.channel.trigger_typing()
 | 
				
			||||||
 | 
								ctx_id = ctx.channel.id
 | 
				
			||||||
			await purgeGames(ctx=ctx, timeslot=timeslot)
 | 
								await purgeGames(ctx=ctx, timeslot=timeslot)
 | 
				
			||||||
 | 
								if discord.utils.find(lambda x: x.id == ctx_id, ctx.guild.text_channels) is not None:
 | 
				
			||||||
				await ctx.send(
 | 
									await ctx.send(
 | 
				
			||||||
					content = f'```All games for time slot `{conf[guildStr]["timeslots"][timeslot]}` have been purged.```',
 | 
										content = f'```All games for time slot `{conf[guildStr]["timeslots"][timeslot]}` have been purged.```',
 | 
				
			||||||
					hidden=True
 | 
										hidden=True
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									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)
 | 
				
			||||||
 | 
										await c.send(
 | 
				
			||||||
 | 
											content = f'```All games for time slot `{conf[guildStr]["timeslots"][timeslot]}` have been purged.```'
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
		yaml_dump(gms,gmFile)
 | 
							yaml_dump(gms,gmFile)
 | 
				
			||||||
		yaml_dump(lookup,lookupFile)
 | 
							yaml_dump(lookup,lookupFile)
 | 
				
			||||||
		yaml_dump(data,dataFile)
 | 
							yaml_dump(data,dataFile)
 | 
				
			||||||
@@ -498,8 +556,8 @@ class GameManagement(commands.Cog, name='Game Management'):
 | 
				
			|||||||
		if not any([x for x in yaml_load(lookupFile).values()]):
 | 
							if not any([x for x in yaml_load(lookupFile).values()]):
 | 
				
			||||||
			unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
								unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
			if self.client.get_cog('Player Commands') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
								if self.client.get_cog('Player Commands') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
								if self.client.get_cog('Pitch') is not None: unloadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
			await self.client.slash.sync_all_commands()
 | 
								await self.client.slash.sync_all_commands()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
def setup(client):
 | 
					def setup(client):
 | 
				
			||||||
	client.add_cog(GameManagement(client))
 | 
						client.add_cog(GameManagement(client))
 | 
				
			||||||
@@ -93,8 +93,12 @@ class ManipulateTimeslots(commands.Cog, name='Manipulate Timeslots'):
 | 
				
			|||||||
				unloadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
									unloadCog(f'./{cogsDir}/slashcommands/secondary/manipulate_timeslots.py')
 | 
				
			||||||
				if self.client.get_cog('Game Management') is not None:
 | 
									if self.client.get_cog('Game Management') is not None:
 | 
				
			||||||
					unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
										unloadCog(f'./{cogsDir}/slashcommands/secondary/game_management.py')
 | 
				
			||||||
				if self.client.get_cog('Game Setup') is not None:
 | 
									if self.client.get_cog('Game Create') is not None:
 | 
				
			||||||
					unloadCog(f'./{cogsDir}/slashcommands/secondary/game_setup.py')
 | 
										unloadCog(f'./{cogsDir}/slashcommands/secondary/game_create.py')
 | 
				
			||||||
 | 
									if self.client.get_cog('Player Commands') is not None:
 | 
				
			||||||
 | 
										unloadCog(f'./{cogsDir}/slashcommands/secondary/player_commands.py')
 | 
				
			||||||
 | 
									if self.client.get_cog('Pitch') is not None:
 | 
				
			||||||
 | 
										unloadCog(f'./{cogsDir}/slashcommands/secondary/pitch.py')
 | 
				
			||||||
				await self.client.slash.sync_all_commands()
 | 
									await self.client.slash.sync_all_commands()
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			await ctx.send('```Error: You cannot delete a timeslot that has existing game entries. Please delete all games first.```',hidden=True)
 | 
								await ctx.send('```Error: You cannot delete a timeslot that has existing game entries. Please delete all games first.```',hidden=True)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										288
									
								
								app/cogs/slashcommands/secondary/pitch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								app/cogs/slashcommands/secondary/pitch.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
				
			|||||||
 | 
					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, ButtonStyle
 | 
				
			||||||
 | 
					from discord_slash.client import SlashCommand
 | 
				
			||||||
 | 
					from discord_slash.utils.manage_components import create_select, create_select_option, create_actionrow, wait_for_component, create_button, create_actionrow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from bot import configFile, yaml_load, yaml_dump, cogsDir, unloadCog, dataFile, lookupFile, gmFile, categoriesFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Pitch Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Pitch(commands.Cog, name='Pitch Command'):
 | 
				
			||||||
 | 
						def __init__(self, client):
 | 
				
			||||||
 | 
							self.client = client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conf=yaml_load(configFile)
 | 
				
			||||||
 | 
						permissions={}
 | 
				
			||||||
 | 
						guild_ids = list(set.intersection(set([int(guildKey) for guildKey in yaml_load(configFile) if yaml_load(configFile)[guildKey]['timeslots']]),set([int(guildKey) for guildKey in yaml_load(configFile) if 'bot' in yaml_load(configFile)[guildKey]['roles'] and type(yaml_load(configFile)[guildKey]['roles']['bot']) is int])))
 | 
				
			||||||
 | 
						for guildID in guild_ids:
 | 
				
			||||||
 | 
							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))
 | 
				
			||||||
 | 
						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_slash(
 | 
				
			||||||
 | 
							name='pitch',
 | 
				
			||||||
 | 
							description='Designates the various key roles referenced by the Bot.',
 | 
				
			||||||
 | 
							default_permission=False,
 | 
				
			||||||
 | 
							permissions=permissions,
 | 
				
			||||||
 | 
							guild_ids=guild_ids,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						async def _pitch(self, ctx:SlashContext):
 | 
				
			||||||
 | 
							await ctx.channel.trigger_typing()
 | 
				
			||||||
 | 
							conf = yaml_load(configFile)
 | 
				
			||||||
 | 
							data = yaml_load(dataFile)
 | 
				
			||||||
 | 
							lookup = yaml_load(lookupFile)
 | 
				
			||||||
 | 
							gms = yaml_load(gmFile)
 | 
				
			||||||
 | 
							categories = yaml_load(categoriesFile)
 | 
				
			||||||
 | 
							pitches = {}
 | 
				
			||||||
 | 
							guildStr = str(ctx.guild.id)
 | 
				
			||||||
 | 
							if 'timeslots' not in conf[guildStr]: conf[guildStr]['timeslots'] = {}
 | 
				
			||||||
 | 
							tsDict = {k: conf[guildStr]['timeslots'][k] for k in data[guildStr] if data[guildStr][k]}
 | 
				
			||||||
 | 
							optionsList = [create_select_option(label=tsDict[x], value=x, description=x) for x in tsDict]
 | 
				
			||||||
 | 
							try:
 | 
				
			||||||
 | 
								m = await ctx.send(
 | 
				
			||||||
 | 
									content='```Select which time slot for which you would like to run pitches for.```',
 | 
				
			||||||
 | 
									delete_after=5,
 | 
				
			||||||
 | 
									components=[
 | 
				
			||||||
 | 
										create_actionrow(
 | 
				
			||||||
 | 
											create_select(
 | 
				
			||||||
 | 
												placeholder='Time Slot',
 | 
				
			||||||
 | 
												options= optionsList,
 | 
				
			||||||
 | 
												min_values=1,
 | 
				
			||||||
 | 
												max_values=1
 | 
				
			||||||
 | 
											)
 | 
				
			||||||
 | 
										)
 | 
				
			||||||
 | 
									]
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								while True:
 | 
				
			||||||
 | 
									select_ctx = await wait_for_component(self.client,messages=m, timeout=5)
 | 
				
			||||||
 | 
									if select_ctx.author != ctx.author:
 | 
				
			||||||
 | 
										await select_ctx.send(f'```Invalid response: you are not the person who issued the command.```', hidden=True)
 | 
				
			||||||
 | 
									else:
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
								await m.delete()
 | 
				
			||||||
 | 
								[timeslot] = select_ctx.selected_options
 | 
				
			||||||
 | 
							except asyncio.TimeoutError:
 | 
				
			||||||
 | 
								await ctx.send(f'```Error: Command timed out.```', hidden=True)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							await ctx.channel.trigger_typing()
 | 
				
			||||||
 | 
							p = discord.PermissionOverwrite()
 | 
				
			||||||
 | 
							p.read_messages = False
 | 
				
			||||||
 | 
							p.send_messages = False
 | 
				
			||||||
 | 
							await ctx.channel.edit(
 | 
				
			||||||
 | 
								reason=f'/pitch command issued by {ctx.author.display_name}',
 | 
				
			||||||
 | 
								overwrites = {
 | 
				
			||||||
 | 
									ctx.guild.default_role: p
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							if guildStr not in pitches: pitches[guildStr] = {}
 | 
				
			||||||
 | 
							if timeslot not in pitches[guildStr]: pitches[guildStr][timeslot] = {}
 | 
				
			||||||
 | 
							pitches[guildStr][timeslot]['entries'] = [x for x in data[guildStr][timeslot].values()]
 | 
				
			||||||
 | 
							pitches[guildStr][timeslot]['entries'].sort(key= lambda x: x['game_title'])
 | 
				
			||||||
 | 
							header_message = await ctx.channel.send(
 | 
				
			||||||
 | 
								content=f'**Game listing for {conf[guildStr]["timeslots"][timeslot]}**\n_ _```The following are the games that are being pitched. Please select which game you would like to join by clicking on the `Join` button below.```'
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							pitches[guildStr][timeslot]['messages'] = []
 | 
				
			||||||
 | 
							pitches[guildStr][timeslot]['roles'] = {}
 | 
				
			||||||
 | 
							for index, element in enumerate(pitches[guildStr][timeslot]['entries']):
 | 
				
			||||||
 | 
								gm = await self.client.fetch_user(element["gm"])
 | 
				
			||||||
 | 
								o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
 | 
				
			||||||
 | 
								if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
 | 
				
			||||||
 | 
								if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])}	'])
 | 
				
			||||||
 | 
								if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
 | 
				
			||||||
 | 
								if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
 | 
				
			||||||
 | 
								o = ''.join([o,f'```'])
 | 
				
			||||||
 | 
								spaces_remaining = element["max_players"] - element["current_players"]
 | 
				
			||||||
 | 
								o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
 | 
				
			||||||
 | 
								m = await ctx.channel.send(
 | 
				
			||||||
 | 
									content=o,
 | 
				
			||||||
 | 
									components=[
 | 
				
			||||||
 | 
										create_actionrow(
 | 
				
			||||||
 | 
											create_button(
 | 
				
			||||||
 | 
												style=ButtonStyle.green,
 | 
				
			||||||
 | 
												label='Join',
 | 
				
			||||||
 | 
												emoji='🉑',
 | 
				
			||||||
 | 
												custom_id=f'join_{index}'
 | 
				
			||||||
 | 
											),
 | 
				
			||||||
 | 
											create_button(
 | 
				
			||||||
 | 
												style=ButtonStyle.red,
 | 
				
			||||||
 | 
												label='Leave',
 | 
				
			||||||
 | 
												emoji='🈳',
 | 
				
			||||||
 | 
												custom_id=f'leave_{index}'
 | 
				
			||||||
 | 
											)
 | 
				
			||||||
 | 
										)
 | 
				
			||||||
 | 
									]
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								pitches[guildStr][timeslot]['messages'].append(m)
 | 
				
			||||||
 | 
								pitches[guildStr][timeslot]['roles'][index] = discord.utils.find(lambda x: x.id == element['role'],ctx.guild.roles)
 | 
				
			||||||
 | 
							newcomer = returning_player = None
 | 
				
			||||||
 | 
							if 'newcomer' in conf[guildStr]['roles']: newcomer = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['newcomer'], ctx.guild.roles)
 | 
				
			||||||
 | 
							if 'returning_player' in conf[guildStr]['roles']: returning_player = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['returning_player'], ctx.guild.roles)
 | 
				
			||||||
 | 
							buttons = []
 | 
				
			||||||
 | 
							if returning_player is not None:
 | 
				
			||||||
 | 
								buttons.append(
 | 
				
			||||||
 | 
									create_button(
 | 
				
			||||||
 | 
										style= ButtonStyle.grey,
 | 
				
			||||||
 | 
										label= 'Allow Returning Players',
 | 
				
			||||||
 | 
										emoji= '🔁',
 | 
				
			||||||
 | 
										custom_id='allow_returning'
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							if newcomer is not None:
 | 
				
			||||||
 | 
								buttons.append(
 | 
				
			||||||
 | 
									create_button(
 | 
				
			||||||
 | 
										style= ButtonStyle.grey,
 | 
				
			||||||
 | 
										label= 'Allow Newcomers',
 | 
				
			||||||
 | 
										emoji= '🆕',
 | 
				
			||||||
 | 
										custom_id='allow_newcomers'
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							buttons.append(
 | 
				
			||||||
 | 
								create_button(
 | 
				
			||||||
 | 
									style= ButtonStyle.green,
 | 
				
			||||||
 | 
									label= 'Allow All',
 | 
				
			||||||
 | 
									emoji='🚪',
 | 
				
			||||||
 | 
									custom_id='allow_all'
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							buttons.append(
 | 
				
			||||||
 | 
								create_button(
 | 
				
			||||||
 | 
									style= ButtonStyle.red,
 | 
				
			||||||
 | 
									label= 'Close Pitches',
 | 
				
			||||||
 | 
									emoji='🔒',
 | 
				
			||||||
 | 
									custom_id='close_pitches'
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							control = await ctx.channel.send(
 | 
				
			||||||
 | 
								content='_ _\n```Control Panel:\nFor Admin Use Only```',
 | 
				
			||||||
 | 
								components=[
 | 
				
			||||||
 | 
									create_actionrow(
 | 
				
			||||||
 | 
										*buttons
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
								]
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							while True:
 | 
				
			||||||
 | 
								button_ctx = await wait_for_component(
 | 
				
			||||||
 | 
									self.client,
 | 
				
			||||||
 | 
									messages=pitches[guildStr][timeslot]['messages'] + [control]
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								if button_ctx.origin_message.id == control.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):
 | 
				
			||||||
 | 
										await button_ctx.send(f'```Error: You are not authorised to do this. The control panel may only be issued by an administrator.```',hidden=True)
 | 
				
			||||||
 | 
									else:
 | 
				
			||||||
 | 
										if button_ctx.custom_id == 'allow_returning':
 | 
				
			||||||
 | 
											await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=returning_player, read_messages=True)
 | 
				
			||||||
 | 
											await button_ctx.send(f'```Returning Players have now been allowed access to the pitch menu.```',  hidden=True)
 | 
				
			||||||
 | 
										if button_ctx.custom_id == 'allow_newcomers':
 | 
				
			||||||
 | 
											ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=newcomer, read_messages=True)
 | 
				
			||||||
 | 
											await button_ctx.send(f'```Newcomers have now been allowed access to the pitch menu.```',  hidden=True)
 | 
				
			||||||
 | 
										if button_ctx.custom_id == 'allow_all':
 | 
				
			||||||
 | 
											await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', target=ctx.guild.default_role, read_messages= True, send_messages=False)
 | 
				
			||||||
 | 
											await button_ctx.send(f'```All members have now been allowed access to the pitch menu.```', hidden=True)
 | 
				
			||||||
 | 
										if button_ctx.custom_id == 'close_pitches': break
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									index = int(button_ctx.custom_id.split('_',1)[1])
 | 
				
			||||||
 | 
									if button_ctx.custom_id.startswith('join_'):
 | 
				
			||||||
 | 
										if set(button_ctx.author.roles) & set(pitches[guildStr][timeslot]['roles']):
 | 
				
			||||||
 | 
											for role in list(set(button_ctx.author.roles) & set(pitches[guildStr][timeslot]['roles'])):
 | 
				
			||||||
 | 
												if role != pitches[guildStr][timeslot]['roles'][index]:
 | 
				
			||||||
 | 
													await button_ctx.author.remove_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
 | 
				
			||||||
 | 
													data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
 | 
				
			||||||
 | 
													element = pitches[guildStr][timeslot]['entries'][index]
 | 
				
			||||||
 | 
													gm = await self.client.fetch_user(element['gm'])
 | 
				
			||||||
 | 
													o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
 | 
				
			||||||
 | 
													if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
 | 
				
			||||||
 | 
													if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])}	'])
 | 
				
			||||||
 | 
													if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
 | 
				
			||||||
 | 
													if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
 | 
				
			||||||
 | 
													o = ''.join([o,f'```'])
 | 
				
			||||||
 | 
													spaces_remaining = element["max_players"] - element["current_players"]
 | 
				
			||||||
 | 
													o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
 | 
				
			||||||
 | 
													await pitches[guildStr][timeslot]['messages'][index].edit(content=o)
 | 
				
			||||||
 | 
													tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
 | 
				
			||||||
 | 
													if tc is None:
 | 
				
			||||||
 | 
														c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
 | 
				
			||||||
 | 
														if c is not None:
 | 
				
			||||||
 | 
															tPos = len(ctx.guild.channels)
 | 
				
			||||||
 | 
															for t in c.text_channels:
 | 
				
			||||||
 | 
																if t.position <= tPos:
 | 
				
			||||||
 | 
																	tc = t
 | 
				
			||||||
 | 
																	tPos = t.position
 | 
				
			||||||
 | 
													if tc is not None:
 | 
				
			||||||
 | 
														await tc.send(f'```{button_ctx.author.display_name} has left the game.```')
 | 
				
			||||||
 | 
										role = pitches[guildStr][timeslot]['roles'][index]
 | 
				
			||||||
 | 
										if role in button_ctx.author.roles:
 | 
				
			||||||
 | 
											await button_ctx.send(f'```Error: You are already in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
 | 
				
			||||||
 | 
										else:
 | 
				
			||||||
 | 
											await button_ctx.author.add_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
 | 
				
			||||||
 | 
											data[guildStr][timeslot][str(role.id)]['current_players'] += 1
 | 
				
			||||||
 | 
											element = pitches[guildStr][timeslot]['entries'][index]
 | 
				
			||||||
 | 
											gm = await self.client.fetch_user(element['gm'])
 | 
				
			||||||
 | 
											o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
 | 
				
			||||||
 | 
											if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
 | 
				
			||||||
 | 
											if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])}	'])
 | 
				
			||||||
 | 
											if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
 | 
				
			||||||
 | 
											if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
 | 
				
			||||||
 | 
											o = ''.join([o,f'```'])
 | 
				
			||||||
 | 
											spaces_remaining = element["max_players"] - element["current_players"]
 | 
				
			||||||
 | 
											o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
 | 
				
			||||||
 | 
											await pitches[guildStr][timeslot]['messages'][index].edit(content=o)
 | 
				
			||||||
 | 
											await button_ctx.send(f'You have joined the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
 | 
				
			||||||
 | 
											tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
 | 
				
			||||||
 | 
											if tc is None:
 | 
				
			||||||
 | 
												c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
 | 
				
			||||||
 | 
												if c is not None:
 | 
				
			||||||
 | 
													tPos = len(ctx.guild.channels)
 | 
				
			||||||
 | 
													for t in c.text_channels:
 | 
				
			||||||
 | 
														if t.position <= tPos:
 | 
				
			||||||
 | 
															tc = t
 | 
				
			||||||
 | 
															tPos = t.position
 | 
				
			||||||
 | 
											if tc is not None:
 | 
				
			||||||
 | 
												await tc.send(f'```{button_ctx.author.display_name} has joined the game.```')
 | 
				
			||||||
 | 
									elif button_ctx.custom_id.startswith('leave_'):
 | 
				
			||||||
 | 
										role = pitches[guildStr][timeslot]['roles'][index]
 | 
				
			||||||
 | 
										if role not in button_ctx.author.roles:
 | 
				
			||||||
 | 
											await button_ctx.send(f'```Error: You are not in the game `{lookup[guildStr][str(role.id)]["game_title"]}`.```', hidden=True)
 | 
				
			||||||
 | 
										else:
 | 
				
			||||||
 | 
											await button_ctx.author.remove_roles(role,reason=f'/pitch interaction by {button_ctx.author.display_name}')
 | 
				
			||||||
 | 
											data[guildStr][timeslot][str(role.id)]['current_players'] -= 1
 | 
				
			||||||
 | 
											element = pitches[guildStr][timeslot]['entries'][index]
 | 
				
			||||||
 | 
											gm = await self.client.fetch_user(element['gm'])
 | 
				
			||||||
 | 
											o = f'_ _\n***{element["game_title"]}*** (GM: {gm.mention})\n```\n'
 | 
				
			||||||
 | 
											if element['system'] is not None: o = ''.join([o,f'System: {element["system"]}\n'])
 | 
				
			||||||
 | 
											if element['min_players'] is not None: o = ''.join([o,f'Minimum Players: {str(element["min_players"])}	'])
 | 
				
			||||||
 | 
											if element['max_players'] is not None: o = ''.join([o,f'Maximum Players: {str(element["max_players"])}\n'])
 | 
				
			||||||
 | 
											if element['platform'] is not None: o = ''.join([o,f'Platform: {element["platform"]}\n'])
 | 
				
			||||||
 | 
											o = ''.join([o,f'```'])
 | 
				
			||||||
 | 
											spaces_remaining = element["max_players"] - element["current_players"]
 | 
				
			||||||
 | 
											o = ''.join([o,f'~~Spaces Remaining: {str(0)}~~'])if spaces_remaining <= 0 else ''.join([o,f'Spaces Remaining: {str(spaces_remaining)}'])
 | 
				
			||||||
 | 
											await pitches[guildStr][timeslot]['messages'][index].edit(content=o)
 | 
				
			||||||
 | 
											await button_ctx.send(f'You have left the game `{lookup[guildStr][str(role.id)]["game_title"]}`.',hidden=True)
 | 
				
			||||||
 | 
											tc = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['text_channel'],ctx.guild.text_channels)
 | 
				
			||||||
 | 
											if tc is None:
 | 
				
			||||||
 | 
												c = discord.utils.find(lambda x: x.id == lookup[guildStr][str(role.id)]['category'],ctx.guild.categories)
 | 
				
			||||||
 | 
												if c is not None:
 | 
				
			||||||
 | 
													tPos = len(ctx.guild.channels)
 | 
				
			||||||
 | 
													for t in c.text_channels:
 | 
				
			||||||
 | 
														if t.position <= tPos:
 | 
				
			||||||
 | 
															tc = t
 | 
				
			||||||
 | 
															tPos = t.position
 | 
				
			||||||
 | 
											if tc is not None:
 | 
				
			||||||
 | 
												await tc.send(f'```{button_ctx.author.display_name} has left the game.```')
 | 
				
			||||||
 | 
								yaml_dump(data, dataFile)
 | 
				
			||||||
 | 
							await header_message.delete()
 | 
				
			||||||
 | 
							for message in pitches[guildStr][timeslot]['messages']: await message.delete()
 | 
				
			||||||
 | 
							await control.delete()
 | 
				
			||||||
 | 
							await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', overwrites={})
 | 
				
			||||||
 | 
							await button_ctx.send('```Pitch menu cleared. Pitches have now been concluded.```')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def setup(client):
 | 
				
			||||||
 | 
						client.add_cog(Pitch(client))
 | 
				
			||||||
@@ -9,7 +9,8 @@ from discord_slash.model import SlashCommandPermissionType
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from bot import configFile, yaml_load, yaml_dump, lookupFile, dataFile, gmFile, categoriesFile
 | 
					from bot import configFile, yaml_load, yaml_dump, lookupFile, dataFile, gmFile, categoriesFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##### Game Management Commands
 | 
					##### Player Add, Remove, and Leave Commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
					class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			||||||
	def __init__(self, client):
 | 
						def __init__(self, client):
 | 
				
			||||||
		self.client = client
 | 
							self.client = client
 | 
				
			||||||
@@ -81,9 +82,9 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
				header = discord.utils.find(lambda x: x.id == hm, p)
 | 
									header = discord.utils.find(lambda x: x.id == hm, p)
 | 
				
			||||||
				if header is not None:
 | 
									if header is not None:
 | 
				
			||||||
					text = header.content.split('\n')
 | 
										text = header.content.split('\n')
 | 
				
			||||||
					for line in text:
 | 
										for line, item in enumerate(text):
 | 
				
			||||||
						if 'Current Players: ' in line:
 | 
											if 'Current Players: ' in item:
 | 
				
			||||||
							line = f'Current Players: {str(data[guildStr][t][rStr]["current_players"])}'
 | 
												text[line] = f'Current Players: {str(data[guildStr][t][rStr]["current_players"])}'
 | 
				
			||||||
							break
 | 
												break
 | 
				
			||||||
					await header.edit(content='\n'.join(text))
 | 
										await header.edit(content='\n'.join(text))
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
@@ -135,9 +136,6 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		game = discord.utils.find(lambda x: x.id == categories[guildStr][str(ctx.channel.category.id)], ctx.guild.roles)
 | 
							game = discord.utils.find(lambda x: x.id == categories[guildStr][str(ctx.channel.category.id)], ctx.guild.roles)
 | 
				
			||||||
		rStr = str(game.id)
 | 
							rStr = str(game.id)
 | 
				
			||||||
		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
 | 
					 | 
				
			||||||
		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 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 not set(ctx.author.roles) & set([ctx.guild.get_role(int(x)) for x in gms[str(ctx.guild.id)] if gms[str(ctx.guild.id)][x]]):
 | 
								if not set(ctx.author.roles) & set([ctx.guild.get_role(int(x)) for x in gms[str(ctx.guild.id)] if gms[str(ctx.guild.id)][x]]):
 | 
				
			||||||
				await ctx.send(f'```Error: You are not authorised to issue this command. The command may only be issued by an administrator or by a GM.```',hidden=True)
 | 
									await ctx.send(f'```Error: You are not authorised to issue this command. The command may only be issued by an administrator or by a GM.```',hidden=True)
 | 
				
			||||||
@@ -145,6 +143,9 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
			if ctx.author.id != lookup[guildStr][rStr]['gm']:
 | 
								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)
 | 
									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
 | 
									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}`.')
 | 
							await player.remove_roles(game, reason=f'`/player remove` command issued by {ctx.author.display_name}`.')
 | 
				
			||||||
		t = lookup[guildStr][rStr]['time']
 | 
							t = lookup[guildStr][rStr]['time']
 | 
				
			||||||
		if data[guildStr][t][rStr]['current_players'] <= 1: data[guildStr][t][rStr]['current_players'] = None
 | 
							if data[guildStr][t][rStr]['current_players'] <= 1: data[guildStr][t][rStr]['current_players'] = None
 | 
				
			||||||
@@ -157,9 +158,9 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
				header = discord.utils.find(lambda x: x.id == hm, p)
 | 
									header = discord.utils.find(lambda x: x.id == hm, p)
 | 
				
			||||||
				if header is not None:
 | 
									if header is not None:
 | 
				
			||||||
					text = header.content.split('\n')
 | 
										text = header.content.split('\n')
 | 
				
			||||||
					for line in text:
 | 
										for line, item in enumerate(text):
 | 
				
			||||||
						if 'Current Players: ' in line:
 | 
											if 'Current Players: ' in item:
 | 
				
			||||||
							line = f'Current Players: {str(data[guildStr][t][rStr]["current_players"]) if data[guildStr][t][rStr]["current_players"] is not None else str(0)}'
 | 
												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
 | 
												break
 | 
				
			||||||
					await header.edit(content='\n'.join(text))
 | 
										await header.edit(content='\n'.join(text))
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
@@ -198,12 +199,12 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
		guildStr = str(ctx.guild.id)
 | 
							guildStr = str(ctx.guild.id)
 | 
				
			||||||
		player = ctx.author
 | 
							player = ctx.author
 | 
				
			||||||
		if str(ctx.channel.category.id) not in categories[guildStr]:
 | 
							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)
 | 
								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
 | 
								return
 | 
				
			||||||
		game = categories[guildStr][str(ctx.channel.category.id)]
 | 
							game = discord.utils.find(lambda x: x.id == categories[guildStr][str(ctx.channel.category.id)], ctx.guild.roles)
 | 
				
			||||||
		rStr = str(game.id)
 | 
							rStr = str(game.id)
 | 
				
			||||||
		if game not in player.roles:
 | 
							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)
 | 
								await ctx.send(f'```Error: You are not in the game {lookup[guildStr][rStr]["game_title"]}.```',hidden=True)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		await player.remove_roles(game, reason=f'`/player leave` command issued by {ctx.author.display_name}`.')
 | 
							await player.remove_roles(game, reason=f'`/player leave` command issued by {ctx.author.display_name}`.')
 | 
				
			||||||
		t = lookup[guildStr][rStr]['time']
 | 
							t = lookup[guildStr][rStr]['time']
 | 
				
			||||||
@@ -217,9 +218,9 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
				header = discord.utils.find(lambda x: x.id == hm, p)
 | 
									header = discord.utils.find(lambda x: x.id == hm, p)
 | 
				
			||||||
				if header is not None:
 | 
									if header is not None:
 | 
				
			||||||
					text = header.content.split('\n')
 | 
										text = header.content.split('\n')
 | 
				
			||||||
					for line in text:
 | 
										for line, item in enumerate(text):
 | 
				
			||||||
						if 'Current Players: ' in line:
 | 
											if 'Current Players: ' in item:
 | 
				
			||||||
							line = f'Current Players: {str(data[guildStr][t][rStr]["current_players"]) if data[guildStr][t][rStr]["current_players"] is not None else str(0)}'
 | 
												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
 | 
												break
 | 
				
			||||||
					await header.edit(content='\n'.join(text))
 | 
										await header.edit(content='\n'.join(text))
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
@@ -229,7 +230,7 @@ class PlayerCommands(commands.Cog, name='Player Commands'):
 | 
				
			|||||||
				if t.position <= tPos:
 | 
									if t.position <= tPos:
 | 
				
			||||||
					tc = t
 | 
										tc = t
 | 
				
			||||||
					tPos = t.position
 | 
										tPos = t.position
 | 
				
			||||||
		await tc.send(f'```Player {player.display_name} has left the game.```\n{game.mention}')
 | 
							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']:
 | 
							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)
 | 
								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)
 | 
								r = discord.utils.find(lambda x: x.id == conf[guildStr]['roles']['committee'], ctx.guild.roles)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,2 @@
 | 
				
			|||||||
'864651943820525609':
 | 
					'864651943820525609':
 | 
				
			||||||
  '866788661026488352': 866788659839238164
 | 
					  '867789192527478800': 867789191156203550
 | 
				
			||||||
  '867516972496060446': 867516971017175070
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,4 +21,5 @@
 | 
				
			|||||||
    returning_player: 866645365524660224
 | 
					    returning_player: 866645365524660224
 | 
				
			||||||
    student: 866645394699714570
 | 
					    student: 866645394699714570
 | 
				
			||||||
  timeslots:
 | 
					  timeslots:
 | 
				
			||||||
    suneve: Sunday Evening
 | 
					    avatar: Avatar Time
 | 
				
			||||||
 | 
					    shera: She Ra Time
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,14 @@
 | 
				
			|||||||
'864651943820525609':
 | 
					'864651943820525609':
 | 
				
			||||||
  suneve:
 | 
					  avatar:
 | 
				
			||||||
    '866788659839238164':
 | 
					    '867789191156203550':
 | 
				
			||||||
      category: 866788661026488352
 | 
					      category: 867789192527478800
 | 
				
			||||||
      current_players: null
 | 
					      current_players: 0
 | 
				
			||||||
      game_title: Avatar Legends
 | 
					 | 
				
			||||||
      gm: 493694762210033664
 | 
					 | 
				
			||||||
      header_message: 866825474252210196
 | 
					 | 
				
			||||||
      max_players: 6
 | 
					 | 
				
			||||||
      min_players: null
 | 
					 | 
				
			||||||
      platform: null
 | 
					 | 
				
			||||||
      role: 866788659839238164
 | 
					 | 
				
			||||||
      system: null
 | 
					 | 
				
			||||||
      text_channel: 866788663194812446
 | 
					 | 
				
			||||||
    '867516971017175070':
 | 
					 | 
				
			||||||
      category: 867516972496060446
 | 
					 | 
				
			||||||
      current_players: 1
 | 
					 | 
				
			||||||
      game_title: Masks
 | 
					      game_title: Masks
 | 
				
			||||||
      gm: 493694762210033664
 | 
					      gm: 864649599671205914
 | 
				
			||||||
      header_message: 867517905620303894
 | 
					      header_message: 867789196534349826
 | 
				
			||||||
      max_players: 5
 | 
					      max_players: 5
 | 
				
			||||||
      min_players: null
 | 
					      min_players: null
 | 
				
			||||||
      platform: null
 | 
					      platform: null
 | 
				
			||||||
      role: 867516971017175070
 | 
					      role: 867789191156203550
 | 
				
			||||||
      system: null
 | 
					      system: null
 | 
				
			||||||
      text_channel: 867516974212055060
 | 
					      text_channel: 867789194784407552
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,3 @@
 | 
				
			|||||||
'864651943820525609':
 | 
					'864651943820525609':
 | 
				
			||||||
  '493694762210033664':
 | 
					  '864649599671205914':
 | 
				
			||||||
  - 866788659839238164
 | 
					  - 867789191156203550
 | 
				
			||||||
  - 867516971017175070
 | 
					 | 
				
			||||||
  '864649599671205914': []
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,7 @@
 | 
				
			|||||||
'864651943820525609':
 | 
					'864651943820525609':
 | 
				
			||||||
  '866788659839238164':
 | 
					  '867789191156203550':
 | 
				
			||||||
    category: 866788661026488352
 | 
					    category: 867789192527478800
 | 
				
			||||||
    game_title: Avatar Legends
 | 
					 | 
				
			||||||
    gm: 493694762210033664
 | 
					 | 
				
			||||||
    text_channel: 866788663194812446
 | 
					 | 
				
			||||||
    time: suneve
 | 
					 | 
				
			||||||
  '867516971017175070':
 | 
					 | 
				
			||||||
    category: 867516972496060446
 | 
					 | 
				
			||||||
    game_title: Masks
 | 
					    game_title: Masks
 | 
				
			||||||
    gm: 493694762210033664
 | 
					    gm: 864649599671205914
 | 
				
			||||||
    text_channel: 867516974212055060
 | 
					    text_channel: 867789194784407552
 | 
				
			||||||
    time: suneve
 | 
					    time: avatar
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user