2
votes

So I am new to programming. I decide to take on a project to help me learn how to code. I am currently working on a discord bot using discord.py to create a game similar to the mobile game "BitLife". However, I am running into an issue where I run a command to restart my life and then start a new one directly afterwards and each message is repeated twice.

Here is a simplified version of my code:

import discord
from discord.ext import commands
import asyncio

bot = discord.Client()

TOKEN = 'bot_token'
yesno = ['✅', '❌']

@bot.event
async def on_message(message):

    if (message.content.lower() == 'lb! startlife') or (message.content.lower() == 'lb! sl'):
        if life == 0 or life == None:
            life = 1

            #Variables get set up here, such as age

            age = 0

            await gameRun(message, life)
        else:
            embed=discord.Embed(title='Hold On!', description='You already have a life started! Please use "LB! ContinueLife" to continue you life, or "LB! Reset" to restart your life.', color=0x0000ff)
            await message.reply(embed=embed)
    elif (message.content.lower() == 'lb! endlife') or (message.content.lower() == 'lb! el'):
        if life == 1:
            embed=discord.Embed(title='Are You Sure?', description='You are about to commit suicide and end your life. This CANNOT be reversed. \n\nTo confirm your death, please react with :white_check_mark: below, to cancel, please react with :x: \n\nAction will be canceled automatically after 1 minute!', color=0x0000ff)
            botmsg = await message.reply(embed=embed)
            for emoji in yesno:
                await botmsg.add_reaction(emoji)

            def check(reaction, user):
                return user == message.author and (str(reaction.emoji) == '✅' or str(reaction.emoji) == '❌')

            try:  
                reaction, user = await bot.wait_for('reaction_add', timeout=60.0, check=check)
            except asyncio.TimeoutError: 
                await message.reply('Action canceled ❌')
            else:    
                if reaction.emoji == '✅':
                    life = 0
                    commandLoop = 0
                    
                    #Death message

                elif reaction.emoji == '❌':
                    await message.reply('Action canceled ❌')      
        else:
            embed=discord.Embed(title='Hold On!', description='You have no life to end! Begin your life by doing "LB! StartLife"', color=0x0000ff)
            await message.reply(embed=embed)
    elif (message.content.lower() == 'lb! continuelife') or (message.content.lower() == 'lb! cl'):
        if life == 1:
            if commandLoop == 0:
                await gameRun(message, life)
            else:
                embed=discord.Embed(title='Hold On!', description='You already have a game active. Please wait for the game to timeout to use this command', color=0x0000ff)
                await message.reply(embed=embed)
        else:
            embed=discord.Embed(title='Hold On!', description='You have no life to continue! Please use "LB! StartLife" to start your life.', color=0x0000ff)
            await message.reply(embed=embed)

async def gameRun(message, life):

    commandLoop = 1
    while (life == 1) and (commandLoop == 1):

        if (age == 0) and (age < 1):
            
            #Embed is set up here for users to view their stats

            botmsg = await message.reply(embed=embed)
            
            await botmsg.add_reaction('????')

            def check(reaction, user):
                return user == message.author and (str(reaction.emoji) == '????')

            try:  
                reaction, user = await bot.wait_for('reaction_add', timeout=120.0, check=check)
            except asyncio.TimeoutError:
                commandLoop = 0
                await message.reply('Action timed out, please use "LB! ContinueLife" to continue')
            else:     
                elif reaction.emoji == '????':
                    age = age + 1
        
        elif (age[id] >= 1) and (age[id] < 4):
            #Same proccess is repeated just with more options
        elif (age[id] >= 4) and (age[id] < 16):
            #Same proccess is repeated just with more options
        elif (age[id] >= 16) and (age[id] < 18):
           #Same proccess is repeated just with more options
        else:
            #Same proccess is repeated just with more options

I'm almost certain that the reason the messages are repeating is due to the code still waiting for the user to react from the await in "reaction, user = await bot.wait_for('reaction_add', timeout=120.0, check=check)". I need the await in order for the bot to work correctly. I need to know how to get around the await when I use the "LB! EndLife" command.

Here are some pictures that show what happens:

Image 1: First LB! StartLife command Works fine. Click the reaction, age up, and view the next year's info

Image 2: LB! EndLife command Ends the life fine as it should

Image 3: Using the LB! StartLife again right after ending the previous life This is when the bug happens. As shown, when the user reacts, the responding bot message is repeated

Image 4: Reverts back after a timeout Everything works fine after the timeout. This is what's letting me know that is the "await" that is causing this

1

1 Answers

0
votes

I recommend you to use the commands extension, so you can actually write commands, instead of doing everything in an on_message event. To use that, you'll need commands.Bot instead of discord.Client

Take a look here: https://gist.github.com/dank-tagg/42349435b675573094c5891ce7605f0f

That is so much easier, right? If you run into any problems, just comment beneath the gist.