I wanted to make a rock paper scissor game for my bot:
The bot creates an embed with instructions and reacts with a "rock", "paper", and "scissor" emoji, which the user has to click to input his/her choice.
But the problem is that the code doesn't go any further and shows an error.
Here is the code:
#client.command(aliases = ["rock_paper_scissors","rps"])
async def _rps(ctx): #rps is short for rock, paper, scissor
emojis = ['✊', '🖐️', '✌️']
embedVar = discord.Embed(title="CHOOSE YOUR WEAPON!",description = "Choose between rock, paper, or scissors, {}." . format(ctx.author.mention), color = 0xff9900)
embedVar.add_field(name=":fist: ROCK", value="React with :fist: emoji to choose rock.", inline = False)
embedVar.add_field(name=":hand_splayed: PAPER", value="React with :hand_splayed: emoji to choose paper.", inline = False)
embedVar.add_field(name=":v: SCISSORS", value="React with :v: emoji to choose scissors.", inline = False)
emb = await ctx.send(embed = embedVar)
for emoji in emojis:
await emb.add_reaction(emoji)
def chk(reaction):
return reaction.emb == emb and reaction.channel == ctx.channel
react = await client.wait_for('reaction_add', check=chk)
if react == '✊':
await ctx.send("You chose rock!")
elif react == '🖐️':
await ctx.send("You chose paper!")
elif react == '✌️':
await ctx.send("You chose scissors!")
I am getting this error:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: chk() takes 1 positional argument but 2 were given
I tried many fixes but in vain.
Also, I want the bot to accept the input only from the user who had asked for the rock paper scissor game by the command in the first place (the author of the message, in other words), But I am not sure how to implement that, I tried, but it did not work.
How can I fix this?
reaction_add gives a tuple of a reaction and a user so in the chk function you need to have both the reaction and user. You should also use and user == ctx.author within the chk function to ensure the user is the same.
#client.command(aliases = ["rock_paper_scissors","rps"])
async def _rps(ctx): #rps is short for rock, paper, scissor
emojis = ['✊', '🖐️', '✌️']
embedVar = discord.Embed(title="CHOOSE YOUR WEAPON!",description = "Choose between rock, paper, or scissors, {}." . format(ctx.author.mention), color = 0xff9900)
embedVar.add_field(name=":fist: ROCK", value="React with :fist: emoji to choose rock.", inline = False)
embedVar.add_field(name=":hand_splayed: PAPER", value="React with :hand_splayed: emoji to choose paper.", inline = False)
embedVar.add_field(name=":v: SCISSORS", value="React with :v: emoji to choose scissors.", inline = False)
emb = await ctx.send(embed = embedVar)
for emoji in emojis:
await emb.add_reaction(emoji)
def chk(reaction, user):
return reaction.emb == emb and reaction.channel == ctx.channel and user == ctx.author
react, user = await client.wait_for('reaction_add', check=chk)
if react == '✊':
await ctx.send("You chose rock!")
elif react == '🖐️':
await ctx.send("You chose paper!")
elif react == '✌️':
await ctx.send("You chose scissors!")
Related
I'm making a discord bot using discord.py that plays mini-games with a user. The game is working well but while I was debugging it I found out that while the bot is waiting for input from a command and the user enters another command from the same bot, the bot executes the two commands simultaneously. Is there a way to program the bot so that when a command is made and it is currently running a command it should stop the former and execute the latter command without interfering in the games of other users. Just like the way #Pancake is made.
Below is the command for one of the mini-games (Rock, Paper, Scissors).
#bot.command(name="rps", description="Starts a rock, paper, scissors game against the computer")
async def rock_paper_scissors(ctx):
"""Play a game of Rock, Paper, Scissors against the computer"""
print("Game started!") # debug
user_dm = await bot.create_dm(ctx.author)
await user_dm.send("Enter the number of rounds")
def is_int(message):
return message.content.isdigit() and message.channel == user_dm
rounds = await bot.wait_for('message', check=is_int) # get number of rounds input from user
rounds = int(rounds.content)
human = 0
cpu = 0
for _ in range(rounds): # game loop
computer = random.choice(["rock", "scissors", "paper"])
await user_dm.send("Enter rock, paper or scissors")
def is_rps(message):
return message.content.lower() in ['rock', 'paper', 'scissors'] and message.channel == user_dm
player = await bot.wait_for('message', check=is_rps)
player = player.content
await user_dm.send(f"I chose: {computer}")
win = [('R', 'S'), ('P', 'R'), ('S', 'P')]
player, computer = player[0].upper(), computer[0].upper()
if (player, computer) in win:
await user_dm.send("You won! One Point")
human += 1
elif (computer, player) in win:
await user_dm.send("I won! One Point")
cpu += 1
else:
await user_dm.send("Nobody won! No Point")
if human > cpu:
await user_dm.send(f"You won the game! ({human} -> {cpu})")
elif cpu > human:
await user_dm.send(f"I won the game! ({cpu} -> {human})")
else:
await user_dm.send(f"Draw!!! ({cpu} -> {human})")
So I've been working on my bot with discord.py and it's been working, but when I woke up this morning it wasn't sending any messages but it did every other function. I can't spot the error. It is supposed to respond and change member roles but only the roles change. The bot will not send the embed in the chat. The error is in the image. If anyone is able to find my error it would be greatly appreciated.
if "sign" in message.content:
if message.channel.id == 920821651627712514:
signer=message.author
signee=message.mentions[0].mention
signeeid=message.mentions[0].id
server=bot.get_guild(920821650096812063)
teamsidslist=[920821650180694104]
teamnames=['Philadelphia Eagles']
teamemojis=['AFREagles']
FO = discord.utils.get(message.author.guild.roles, id=920821650285539374)
GM = discord.utils.get(message.author.guild.roles, id=920821650285539373)
HC = discord.utils.get(message.author.guild.roles, id=920821650285539372)
staffroles = [FO, GM, HC]
FA = discord.utils.get(message.author.guild.roles, id=920821650180694097)
Suspended = discord.utils.get(message.author.guild.roles, id=920821650159702055)
roster=[]
agency=[]
teams=[]
for rolesids in message.author.roles:
if rolesids.id in teamsidslist:
teams.append(rolesids.id)
step2=str(teams)
step3=step2.replace("[","")
step4=step3.replace("]","")
print(step4)
step5=teamsidslist.index(int(step4))
print(step5)
emote=discord.utils.get(server.emojis,name=teamemojis[step5])
teamname=teamnames[step5]
team = discord.utils.get(message.author.guild.roles,id=int(step4))
for agents in server.members:
if FA in agents.roles:
agency.append(agents.id)
if signeeid not in agency:
embedno = discord.Embed(title="Transaction Failed!", description=None, color=discord.Color.red())
embedno.add_field(name="This Transaction Couldn't Be Completed.", value="This player is signed already! Have them demand from their team or get released.")
await message.channel.send(embed=embedno)
elif FO in message.author.roles:
for guys in server.members:
if guys.id==signeeid:
await guys.add_roles(team)
await guys.remove_roles(FA)
if Suspended in guys.roles:
await message.channel.send("This player is signable, but is ineligible as they are suspended.")
roster.append(guys)
roster_size=str(len(roster))
SignEmbed= discord.Embed(title="AFR Transactions", description=None, color=discord.Color.green())
SignEmbed.add_field(name='Successful Transaction.', value=signee+" has been signed to the "+str(emote)+" "+teamname+" by "+signer+"!")
SignEmbed.add_field(name="Roster Size is now ", value=roster_size+'/24', inline=True)
await message.channel.send(embed=SignEmbed)
await bot.process_commands(message)
The signer variable is a discord.Member object and you can't concatenate discord.Member to string, i.e (discord.Member + "some string")
also concatenation makes code unreadable and are slow as well. Use f-strings instead.
here is an example:
nice = 3
some_variable = "one two " + str(nice) + " we continue"
print(some_variable)
>>> one two 3 we continue
nice = 3
some_variable = f"one two {nice} we continue"
print(some_variable)
>>> one two 3 we continue
For your issue, just cast signer as string, i.e str(signer)
but I do highly recommend for you to switch to f-strings instead of using concatenation
So I wrote this code that sends an embed and changes its value/item once the user reacts to certain emoji. It works fine for a single embed but when user asks for same multiple embeds like you see in the image, reaction to a embed changes value of other similar embeds too.
Code part
#client.command()
async def embed(ctx):
current = 1
embed = discord.Embed(title = f'{current}')
buttons = [ u"\u25C0", u"\u25FC" , u"\u25B6" , u"\U0001F5D1"]
msg = await ctx.send(embed = embed)
for button in buttons:
await msg.add_reaction(button)
while True:
try:
reaction , user = await client.wait_for("reaction_add", check = lambda reaction,user: user == ctx.author and reaction.emoji in buttons, timeout = 180.0)
except asyncio.TimeoutError:
embed.set_footer(text= "Timeout.")
await msg.clear_reactions()
else:
previous_page = current
if reaction.emoji == u"\u25C0":
current -= 1
embed.add_field(name = None, value = f'{current}')
elif reaction.emoji == u"\u25FC":
if current > 0:
current = 0
embed.add_field(name = None, value = f'{current}')
elif reaction.emoji == u"\u25B6":
current += 1
embed.add_field(name = None, value = f'{current}')
elif reaction.emoji == u"\U0001F5D1":
await msg.edit(embed = embed)
await msg.clear_reactions()
for button in buttons:
await msg.remove_reaction(button, ctx.author)
if current != previous_page:
embed.add_field(name = None, value = f'{current}')
await msg.edit(embed = embed)
Images: https://imgur.com/a/fEpz9jD
NOTE: The code I've used in my bot is exactly same as this one. I haven't included that and screenshots of those embeds because it is being used for NSFW purposes/images.
Thanks.
This may be happening because of your check function (line 13)
check = lambda reaction,user: user == ctx.author and reaction.emoji in buttons
Here you are checking that the emoji are matching, and the user reacting is the same user that executed the command. But you don't check which message the reaction was added to. To solve this, you could check for the message id, by checking if reaction.message.id == ctx.message.id what results in :
check = lambda reaction,user: user == ctx.author and reaction.emoji in buttons and reaction.message.id == msg.id
im trying to make a random number generator command for discord py which will choose a random number from what the user have send, the first number, user can input any number but the second number, user need to input the bigger number than the first number so the bot will choose a random number between the first and the second number. The command works fine but the number only choose the first or second number and not the random number between the first and second number. Heres the code :
#client.command()
async def randomnumber(ctx):
def check(msg):
return msg.author == ctx.author and msg.content.isdigit() and \
msg.channel == ctx.channel
embed1 = discord.Embed(title = "Random Number Generator!!", description = "<:_Paimon6:827074349450133524>", color = ctx.author.color)
embed1.add_field(name='Type a number', value=f'First Number : Not Yet Added!!!\nSecond Number : Not Yet Added!!!', inline=False)
await ctx.send(embed = embed1)
msg1 = await client.wait_for("message", check=check)
embed2 = discord.Embed(title = "Random Number Generator!!!", description = "<:_Paimon6:827074349450133524>", color = ctx.author.color)
embed2.add_field(name='Type a second number, higher number than first number', value=f'First Number : {msg1.content}\nSecond Number : Not Yet Added!!!', inline=False)
await ctx.send(embed = embed2)
msg2 = await client.wait_for("message", check=check)
x = int(msg1.content)
y = int(msg2.content)
if x < y:
value = (x,y)
embed3 = discord.Embed(title = "Random Number Generator!!", description = "<:_Paimon6:827074349450133524>", color = ctx.author.color)
embed3.add_field(name='Result number', value=f'First Number : {msg1.content}\nSecond Number : {msg2.content}\n\nYou got {random.choice(value)} <:_pTooEaassy:827076106884087818>', inline=False)
await ctx.send(embed = embed3)
else:
embed4 = discord.Embed(title = "Random Number Generator!!", description = "<:_Paimon6:827074349450133524>", color = ctx.author.color)
embed4.add_field(name='Error', value='You didnt enter the number correctly so paimon dont know what to send <:_Paimon10:827077240079777812>', inline=False)
await ctx.send(embed = embed4)
I know that the problem was on the "value" one but idk what should i change there to make the bot choose a random number between the two number, thank you.
You can use the random.randrange function
>>> import random
>>> values = (1, 10) # hardcoding for demonstration purposes
>>> random.randrange(*values) # unpacking the tuple
6
>>> random.randrange(*values)
3
>>> random.randrange(*values)
4
How can I make my Bot Exclude someone from the usage if a user's abusing it (like spamming commands and stuff)
#client.command(pass_context = True, aliases = ['bban'])
#commands.is_owner()
async def botban(ctx, member: discord.Member = None, banreason='Kein Grund angegeben!'):
if member is None:
em = discord.Embed(color = 0xff2200, title = "Argumente Fehlen!",
description = f"{ctx.author.mention} Bitte nenne den User, den du vom Bot ausschließen willst\n\n```py\no?botban [#nutzer / id] [(optional) Grund]\n```\n Optional: ```py\no?bban [#nutzer / id] [(optional) Grund]\n```",
footer = f'User-ID: ' + str(ctx.author.id) + ' Made by Ohnezahn DNC#8135 with discord.py')
em.set_author(name = f'{ctx.author.name}#{ctx.author.discriminator}',
icon_url = f'{ctx.message.author.avatar_url}')
return await ctx.send(embed = em)
elif message.author.id in 'blacklist.json': # Check if user already banned
return await ctx.send(
f"Der Nutzer {member.id} / {member.name} - {member.discriminator} ist bereits ausgeschlossen! Grund:\n\n{banreason}")
elif member.id not in 'ban.json':
with open('ban.json', 'w') as fp:
json.dump(banlist, fp)
emb = discord.Embed(color = 0xff2200, title = "Bot Ban ausgeführt",
description = f'{member.mention} / {member.name}#{member.discriminator} / {member.id} wurde von {ctx.author.name}#{ctx.author.discriminator} / {ctx.author.id} / {ctx.author.mention} vom Bot ausgeschlossen\n\nGrund: {banreason}',
footer = f'User-ID: ' + str(member.id) + '/ Made by Ohnezahn DNC#8135 with discord.py')
emb.set_author(name = f'{ctx.author.name}#{ctx.author.discriminator}',
icon_url = f'{ctx.message.author.avatar_url}')
return await ctx.send(embed = emb)
else:
# Add ban to dict
banlist[member.id] = banreason
# Update File
with open('ban.json', 'w') as fp:
json.dump(banlist, fp)
emb = discord.Embed(color = 0xff2200, title = "Bot Ban ausgeführt",
description = f'{member.mention} / {member.name}#{member.discriminator} / {member.id} wurde von {ctx.author.name}#{ctx.author.discriminator} / {ctx.author.id} / {ctx.author.mention} vom Bot ausgeschlossen\n\nGrund: {banreason}',
footer = f'User-ID: ' + str(member.id) + '/ Made by Ohnezahn DNC#8135 with discord.py')
emb.set_author(name = f'{ctx.author.name}#{ctx.author.discriminator}',
icon_url = f'{ctx.message.author.avatar_url}')
return await ctx.send(embed = emb)
#client.check
def check_commands(ctx):
# Check if user banned, convert id to str because json.load (line 9) load str id's.
return str(ctx.author.id) not in blacklisted_users()
That's how my ban.json looks like at the moment:
{
"blacklistedUsers": [
]
}
that's the codes I have right now... I'm working on this for felt ages right now...
Hello welcome to Stack overflow, There are something in commands called checks. You could add an array the check can see if the user is in that array. If it is don't let them run the command by stopping the command using return
Welcome!
You can do similar thing:
import discord, json
from discord.ext import commands
intents = discord.Intents.default()
bot = commands.Bot(command_prefix='?', intents=intents)
# Load banned data from json
with open('ban.json') as json_file:
bot.banneds = json.load(json_file)
#bot.event
async def on_ready():
print(f'Logged in as {bot.user} (ID: {bot.user.id})')
print('------')
#bot.command()
async def test(ctx): # Only random command for test
await ctx.send("Test okay!")
#bot.command()
#commands.is_owner()
async def ban(ctx, member: discord.Member = None, banreason = 'Empty Reason'):
if member.id in bot.banneds: # Check if user already banned
await ctx.send("Already banned.")
return
else:
# Add ban to dict
bot.banneds[member.id] = banreason
# Update File
with open('ban.json', 'w') as fp:
json.dump(bot.banneds, fp)
await ctx.send(f"{member} has been banned, because {banreason}!")
# Ban Check (Global)
#bot.check
def check_commands(ctx):
# Check if user banned, convert id to str because json.load (line 9) load str id's.
return str(ctx.author.id) not in bot.banneds
bot.run('key')
Create a ban.json at the first time with empty object
{}
Note that if user banned try use commands, you receive error "discord.ext.commands.errors.CheckFailure: The global check functions for command test failed.", add this to your error handler.