forked from viveksantayana/geas-bot
288 lines
15 KiB
Python
288 lines
15 KiB
Python
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':
|
|
await 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.set_permissions(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 concluded.```')
|
|
|
|
def setup(client):
|
|
client.add_cog(Pitch(client)) |