Search code examples
pythondiscord.pydiscord

Discord Bot - How to properly use the same Command (name) twice?


I want users to be able to start a game in a certain channel by doing !readysetgo I want the Bot to tell them that they did that command in the wrong channel (if they're not in the right channel). I then want them to be able to do !dogo in that same channel after the game has started (so after !readysetgo has been done). I want the Bot to tell them if they did !dogo in the wrong channel (if they're not in the right channel) and to tell them the game hasn't started yet and that's why !dogo didn't do anything (if !readysetgo hasn't been done already).

So I have that all setup correctly. It works correctly everywhere except that it doesn't acknowledge when !dogo is run after !readysetgo has run (which is its main purpose).

I know that you can't have two commands with the same name, so I originally worked around that by setting up the command !dogo this way in my code:

Original approach (I prefer this way)

bot.readysetgoGameStarted = False

# User does !dogo but it isn't in the right Channel ; or it is in the right Channel, but the game readysetgo hasn't started yet
@bot.command()
async def dogo(ctx):
    # Makes sure !dogo can only be run in the right channel 
    if ctx.channel.name != "ready-set-go":
        await ctx.reply(f"It looks like you have tried to do the command: **!dogo** which is specific to the Channel: **ready-set-go**. Please go there and try again there")

    elif ctx.channel.name == "ready-set-go": 
        
        # Player did !readysetgo but the Game has already started
        if bot.readysetgoGameStarted == True:
            await ctx.reply("The game has already started, so **!readysetgo** won't do anything")
        
        else: # readysetgo has not been started already, so let it get started and run its logic
            bot.readysetgoGameStarted = True # start the game
            await ctx.channel.send('Ready')
            await asyncio.sleep(1)
            await ctx.channel.send('Set')
            await asyncio.sleep(1)

            Go = False

            # Player does !dogo
            @bot.command(name="innerdogo") # set a name here ; gave it a different one from the command above, but want it to still be called by user doing !dogo which is why I didn't rename below
            async def dogo(ctx):
                print("It worked")

The second approach I thought to try to get it to work was to put all the "verification" code in @bot.event async def on_message(message) looking for message == "!dogo" and then has @bot.command() async def dogo(ctx): inside of the @bot.command() async def readysetgo(ctx):

The problem with this approach is that when a user does !dogo it prints out: Command "dogo" is not found

Second approach

bot.readysetgoGameStarted = False

@bot.event
async def on_message(message):
    # User does !dogo but it isn't in the right Channel ; or it is in the right Channel, but the game readysetgo hasn't started yet
    if message == "!dogo":
        # Makes sure !dogo can only be run in the right channel 
        if message.channel.name != "ready-set-go":
            await message.reply(f"It looks like you have tried to do the command: **!dogo** which is specific to the Channel: **ready-set-go**. Please go there and try again there")
        
        elif message.channel.name == "ready-set-go":
            
            # Player did !dogo but the Game hasn't started
            if bot.readysetgoGameStarted == False:
                await message.reply("Hold your horses, the game hasn't started yet, so **!dogo** won't do anything. If you would like to play, do **!readysetgo** to start a game first")

@bot.command()
async def readysetgo(ctx):
    # Makes sure !readysetgo can only be run in the right channel
    if ctx.channel.name != "ready-set-go":
        await ctx.reply(f"It looks like you have tried to do the command: **!readysetgo** which is specific to the Channel: **ready-set-go**. Please go there and try again there")    
    
    elif ctx.channel.name == "ready-set-go": 
        
        # Player did !readysetgo but the Game has already started
        if bot.readysetgoGameStarted == True:
            await ctx.reply("The game has already started, so **!readysetgo** won't do anything")
        
        else: # readysetgo has not been started already, so let it get started and run its logic
            bot.readysetgoGameStarted = True # start the game
            await ctx.channel.send('Ready')
            await asyncio.sleep(1)
            await ctx.channel.send('Set')
            await asyncio.sleep(1)

            Go = False

            # Player does !dogo
            @bot.command()
            async def dogo(ctx):
                print("It worked")

Is there any way to be able to have !dogo kept consistent so that it works properly? I wonder how other Bots check if a user did a command in the right place or at the right time Thank you


Solution

  • The problem with this is that you can't have a command inside of a command and you also can't name two commands with the same name.

    I'll provide a simple example which you can work with:

    running = False
    
    @bot.command()
    async def readysetgo(ctx:commands.Context):
        global running
        running = True
        await ctx.send("Game is running.")
    
    @bot.command()
    async def dogo(ctx:commands.Context):
        global running
        if running:
            await ctx.send("Your game is running. !dogo executed.")
        else:
            await ctx.send("Please execute readysetgo first.")
    

    Here we use a global variable to determine if the game was started. I did not implement any other logic than the games state, but you already had the other things.