Dom
Dom

Reputation: 138

Discord.py: Use special responses in checks to cause different output

So, this may seem like a bit of an odd question, but I recently created a command for my discord bot that takes the user step-by-step through creating an embed. It works perfectly, but I wanted to implement a way to finish off the command even without all of the fields being filled. So if the user types "finish" while building the embed, it will take them to the part of the building process that asks them what channels they want to send the embed to. Here is my code:

  @embed.command()
  @commands.has_permissions(manage_permissions = True) 
  @commands.bot_has_permissions(manage_permissions = True)
  async def build(self, ctx):

    channel = ctx.channel
    content = f''

    def check(m):
        if m.channel == m.channel and m.content == "CANCEL":
            raise ValueError("Cancelled command")
        return m.content.lower is not None and m.channel == channel and m.content.lower

    # The first round: TITLE

    beggining = await ctx.send('Alright! Let\'s get started! What would you like the **title** of your embed to be?')

    firstin = await self.bot.wait_for("message", check=check)

    await firstin.delete() # Delete the first input

    await beggining.delete()
    firstembed=discord.Embed(title=f'{firstin.content}')

    # The second round: MAIN BODY

    theembed = await ctx.send(content=content, embed=firstembed)

    asking = await ctx.send('Got it! What would you like the **main body** of your embed to be?')

    secondin = await self.bot.wait_for("message", check=check)
    
    await secondin.delete() # Delete the second input

    secondembed=discord.Embed(title=firstin.content, description=secondin.content)
    await theembed.edit(content=content, embed=secondembed)

    await asking.edit(content='Okay. Now, what would you like the **footer** of your embed to be?')

    # The third round: FOOTER

    thirdin = await self.bot.wait_for("message", check=check)

    await thirdin.delete() # Delete the third input

    thirdembed=discord.Embed(title=firstin.content, description=secondin.content)
    thirdembed.set_footer(text=thirdin.content)
    await theembed.edit(content=content, embed=thirdembed)

    await asking.edit(content='Sounds good. Now, what would you like the **hex color code** of your embed to be?')

    # Fourth round: COLOR

    fourthin = await self.bot.wait_for("message", check=check)

    await fourthin.delete() # Delete the fourth input

    readableHex = int(hex(int(fourthin.content.replace("#", ""), 16)), 0)

    fourthembed=discord.Embed(title=firstin.content, description=secondin.content, color=readableHex)
    fourthembed.set_footer(text=thirdin.content)
    await theembed.edit(content=content, embed=fourthembed)

    await asking.edit(content='Cool. What would you like the **image link** of your embed to be?')

    # The fifth round: IMAGE

    fifthin = await self.bot.wait_for("message", check=check)

    await fifthin.delete() # Delete the fifth input

    fifthembed=discord.Embed(title=firstin.content, description=secondin.content, color=readableHex)
    fifthembed.set_footer(text=thirdin.content)
    fifthembed.set_image(url=fifthin.content)
    await theembed.edit(content=content, embed=fifthembed)

    await asking.edit(content='Now, what would you like the **thumbnail image link** of your embed to be?')

    # The sixth round: THUMBNAIL

    sixthin = await self.bot.wait_for("message", check=check)

    await sixthin.delete() # Delete the sixth input

    sixthembed=discord.Embed(title=firstin.content, description=secondin.content, color=readableHex)
    sixthembed.set_footer(text=thirdin.content)
    sixthembed.set_image(url=fifthin.content)
    sixthembed.set_thumbnail(url=sixthin.content)
    await theembed.edit(content=content, embed=sixthembed)

    await asking.edit(content='Now, what would you like the **author name** of your embed to be?')

    # The sevnth round: AUTHOR NAME

    seventhin = await self.bot.wait_for("message", check=check)

    await seventhin.delete() # Delete the seventh input

    seventhembed=discord.Embed(title=firstin.content, description=secondin.content, color=readableHex)
    seventhembed.set_footer(text=thirdin.content)
    seventhembed.set_image(url=fifthin.content)
    seventhembed.set_thumbnail(url=sixthin.content)
    seventhembed.set_author(name=seventhin.content)
    await theembed.edit(content=content, embed=seventhembed)
    
    await asking.edit(content='Almost done! What would you like the **author icon link** of your embed to be? You can also mention someone or yourself to use their avatar.')

    # The eighth round: AUTHOR ICON

    eighthin = await self.bot.wait_for("message", check=check)

    await eighthin.delete() # Delete the eighth input

    if (eighthin.mentions.__len__()>0):
        for user in eighthin.mentions:
            eighthinavatar = user.avatar_url
    else: eighthinavatar = eighthin.content

    eighthembed=discord.Embed(title=firstin.content, description=secondin.content, color=readableHex)
    eighthembed.set_footer(text=thirdin.content)
    eighthembed.set_image(url=fifthin.content)
    eighthembed.set_thumbnail(url=sixthin.content)
    eighthembed.set_author(name=seventhin.content, icon_url=eighthinavatar)
    await theembed.edit(content=content, embed=eighthembed)

    await asking.edit(content='Done! Now please mention the channels you would like to send your embed to!')

    # The ninth round: CHANNELS

    ninthin = await self.bot.wait_for("message", check=check)

    if (ninthin.channel_mentions.__len__()>0):
        for channel in ninthin.channel_mentions:
            await channel.send(content=content, embed=eighthembed)
    
    await ninthin.add_reaction(check_mark)

  @build.error
  async def build_error(self, ctx, error):
    if isinstance(error, commands.errors.CommandInvokeError):
      await ctx.send(f'{x_mark} The embed has been terminated, you will have to start over. This was either due to cancellation or an incorrect argument.')

Is there any way I can do this? Thanks.

Upvotes: 0

Views: 318

Answers (1)

Łukasz Kwieciński
Łukasz Kwieciński

Reputation: 15689

You can create a custom error yourself, CommandInvokeError will be called everytime something fails in the command itself, not the best option imo, here's how:

class CancelledCommand(commands.CheckFailure):
    pass

# Somewhere (in the check func)
raise CancelledCommand('Command has been cancelled')

# In the error handler
if isinstance(error, CancelledCommand):
    ...

Also, 4 things about the check function

  1. str.lower() it's a method, not an attribute, so you need to call it.
  2. m.content will never be None.
  3. m.channel == m.channel doesn't make any sense at all, I think you meant m.channel == ctx.channel
  4. You should probably check for m.author == ctx.author

Here's the check improved:

def check(m):
    if m.channel == ctx.channel and m.author == ctx.author:
        if m.content.lower() == 'finish':
            raise CancelledCommand('Command has been cancelled')
        return True
    return False

Upvotes: 1

Related Questions