2021-07-23 00:44:21 +01:00
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: \n For 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 ' :
2021-07-24 01:01:48 +01:00
await ctx . channel . set_permissions ( reason = f ' /pitch command issued by { ctx . author . display_name } ' , target = newcomer , read_messages = True )
2021-07-23 00:44:21 +01:00
await button_ctx . send ( f ' ```Newcomers have now been allowed access to the pitch menu.``` ' , hidden = True )
if button_ctx . custom_id == ' allow_all ' :
2021-07-24 01:01:48 +01:00
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 )
2021-07-23 00:44:21 +01:00
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 = { } )
2021-07-24 01:01:48 +01:00
await button_ctx . send ( ' ```Pitch menu cleared. Pitches have now concluded.``` ' )
2021-07-23 00:44:21 +01:00
def setup ( client ) :
client . add_cog ( Pitch ( client ) )