get more input from one command (discord.py) - discord

I'm trying to make an embed system that asks multiple questions and then put them together and send the embed with all the info given, but I can't figure out how to get multiple inputs in one command.

Based on what I understand from your question, you're only checking for one possible input with m.content == "hello". You can either remove it or add an in statement. Do view the revised code below.
#commands.command()
async def greet(ctx):
await ctx.send("Say hello!")
def check(m):
return m.channel == channel # only check the channel
# alternatively,
# return m.content.lower() in ["hello", "hey", "hi"] and m.channel == channel
msg = await bot.wait_for("message", check=check)
await ctx.send(f"Hello {msg.author}!")
In the case of the newly edited question, you can access the discord.Message class from the msg variable. For example, you can access the message.content. Do view the code snippet below.
#commands.command()
async def test(ctx):
def check(m):
return m.channel == ctx.channel and m.author == ctx.author
# return message if sent in current channel and author is command author
em = discord.Embed()
await ctx.send("Title:")
msg = await bot.wait_for("message",check=check)
em.title = msg.content
# in this case, you can continue to use the same check function
await ctx.send("Description:")
msg = await bot.wait_for("message",check=check)
em.description = msg.content
await ctx.send(embed=em)

Related

discord.py - How to wait for user input that can be different?

First time posting here, but I just couldn't find what I'm looking for or wrap my head around it.
As of now, I have this:
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content == '!generate':
await message.channel.send(f"{message.author.mention}\n"
f"Sample question: (**Important**: Type a \"!\" in front):\n```"
"> A\n> B\n> C\n> D```")
def check(m):
return m.content == '!A' and m.channel == message.channel
msg = await client.wait_for('message', check=check)
await message.channel.send('Correct!'.format(msg))
So if the user inputs "!generate!", they get a question and a list of available answers. Now the bot already successfully waits for an answer, but only if it's A ("!A") does it actually respond further.
How can I change this so it can be any answer from the list, in this case A, B, C or D?
I already tried this:
def check(m):
sample_list = ['!A', '!B', '!C', '!D']
return m.content == f'{sample_list[0:3]}' and m.channel == message.channel
But that didn't work. To be fair, I'm very new to python and have barely any clue of what I'm doing, so I might be making some stupidly obvious mistake here.
But anyway, I hope this gives a good enough picture of what I'm trying to achieve. I appreciate any help! Thank you!
I think this is what you're looking for :
#bot.command()
async def generate(ctx):
options = ["a", "b", "c", "d"]
already_sent_res = None # Safe to remove, used for demo
await ctx.send(
f"{ctx.author.mention}\n"
f'Sample question: (**Important**: Type a "!" in front):\n```'
"> A\n> B\n> C\n> D```"
)
def check(m):
return (
m.content.startswith("!")
and m.content.lower()[1:] in options
and m.channel.id == ctx.channel.id
)
while True:
msg = await bot.wait_for("message", check=check)
# msg.content now contains the option. You may now proceed to code here
# The below code from here are used for demonstration and can be safely removed
if already_sent_res is None:
sent_message = await ctx.send(
f"**{str(msg.author.name)}** has chosen option **{str(msg.content).upper()[1:]}**"
)
already_sent_res = not None
else:
await sent_message.edit(
f"**{str(msg.author.name)}** has chosen option **{str(msg.content).upper()[1:]}**"
)
Here I used command handling with bot.command() instead of listening under on_message it is fine, you can use any which you are comfortable with.
The above code will result in the following :
Remember that the bot will keep on listening for message event in the channel so be sure to have a timeout or an abort command.
Here's the full code I used incase you need it :
import discord
import os
from discord.ext import commands
bot = commands.Bot(command_prefix="!", case_insensitive=True)
#bot.event
async def on_ready():
print(f"Sucessfully logged in as {bot.user}")
#bot.command()
async def generate(ctx):
options = ["a", "b", "c", "d"]
already_sent_res = None # Safe to remove, used for demo
await ctx.send(
f"{ctx.author.mention}\n"
f'Sample question: (**Important**: Type a "!" in front):\n```'
"> A\n> B\n> C\n> D```"
)
def check(m):
return (
m.content.startswith("!")
and m.content.lower()[1:] in options
and m.channel.id == ctx.channel.id
)
while True:
msg = await bot.wait_for("message", check=check)
# msg.content now contains the option. You may now proceed to code here
# The below code from here are used for demonstration and can be safely removed
if already_sent_res is None:
sent_message = await ctx.send(
f"**{str(msg.author.name)}** has chosen option **{str(msg.content).upper()[1:]}**"
)
already_sent_res = not None
else:
await sent_message.edit(
f"**{str(msg.author.name)}** has chosen option **{str(msg.content).upper()[1:]}**"
)
bot.run(os.getenv("DISCORD_TOKEN"))

Problems with a discord.py bot

I have been trying to code a Discord bot for my own server.
However, it seems like, whenever I add more commands to the code, the ban, and kick functions no longer work correctly.
I've tried rewriting the code multiple times, but it did not work.
I've tried rearranging the codes, and that did not work as well.
client = commands.Bot(command_prefix = '!')
#client.command()
async def kick(ctx, member : discord.Member, *, reason = None):
await member.kick(reason = reason)
#client.command()
async def ban(ctx, member : discord.Member, *, reason = None):
await member.ban(reason = reason)
curseWord = ['die', 'kys', 'are you dumb', 'stfu', 'fuck you', 'nobody cares', 'do i care', 'bro shut up']
def get_quote():
response = requests.get("https://zenquotes.io/api/random")
json_data = json.loads(response.text)
quote = json_data[0]['q'] + " -" + json_data[0]['a']
return(quote)
#ready
#client.event
async def on_ready():
print('LOGGED IN as mr MF {0.user}'.format(client))
#client.event
#detect self messages
async def on_message(message):
if message.author == client.user:
return
#greeting
if message.content.startswith('hello'):
await message.channel.send('ay whatup ma gamer')
#help
if message.content.startswith('!therapy'):
quote = get_quote()
await message.channel.send(quote)
#toxicity begone
msg_content = message.content.lower()
if any(word in msg_content for word in curseWord):
await message.delete()
#environment token
token = os.environ['token']
client.run(token)
You have overwritten the on_message event, which by default processes commands (those marked with the #client.command() decorator). You need to explicitly tell the library to process commands when you overwrite it. As noted in the discord.py documentation, you should add this line at the end of the on_message event:
await client.process_commands(message)

Is there a way could check if an embed is a specific colour or not?

This is what I have been able to come up with after a lot of head scratching and being annoyed but lo and behold, it doesn't work.
import discord
client = discord.Client()
#client.event
async def on_ready():
print("Bot is ready")
#client.event
async def on_message(message):
if (message.channel.id == "the-channel-id-here"):
embeds = message.embeds
if not embeds:
return
else:
embed = (message.embeds)[0]
if (embed.color == 4caf50 or e53935):
print('I got that')
else:
return
client.run(BOT_TOKEN)
discord.py always returns a Color object, rather than an integer, so what you're comparing right now is an instance of Color (as defined here by the way) and a number. The Color object has an attribute value that returns an integer representation of the colour though, so you can use that to compare it to a number instead.
This code snippet should work:
import discord
client = discord.Client()
#client.event
async def on_ready():
print("Bot is ready")
#client.event
async def on_message(message):
if (message.channel.id == "the-channel-id-here"):
embeds = message.embeds
if not embeds:
return
else:
embed = (message.embeds)[0]
if (embed.color.value == 4caf50 or embed.color.value == e53935):
print('I got that')
else:
return
client.run(BOT_TOKEN)
Do note that I modified your if expression slightly, your use of or was wrong, you DO have to repeat embed.color.value again for the comparison to work!

How can I change the order of correct answers or accept more than just one global answer?

I am still working on my question bot and now I want you to be able to give multiple correct_answers. Here is what I had in mind: Each user can execute a command 3x to give an answer. But to each question I want a different solution to be considered correct, so not always just A, as an example. How can I make the bot consider the following answers as correct in the order: A, B, A or A, B, C etc.
At the moment I have the following code:
correct_answers = "A" #Only possibility
#commands.command()
async def answer(self, ctx, answer):
self.answer.enabled = False
global correct_answers
if correct_answers != answer:
await ctx.author.send(f "You guessed {answer} which is **wrong**. Good luck next time!")
await ctx.message.delete()
return
[shortened]
await ctx.message.delete()
await ctx.author.send(f'The right answer was **{correct_answers}**, you guessed **correctly**!')
await asyncio.sleep(10)
self.answer.enabled = True
My embed code where I want to decide after which edit which answer is correct:
#commands.command()
async def trivia_c(self, ctx):
e = discord.Embed(color=discord.Color.gold())
e.title = "New question, new luck."
e.description = "**When was Steve Jobs born?**"
e.add_field(name="1️⃣", value="02/24/1955", inline=False)
e.add_field(name="2️⃣", value="03/24/1955", inline=False)
e.add_field(name="3️⃣", value="02/24/1965", inline=False)
e.set_footer(text="You have x-x to answer this question.", icon_url=self.bot.user.avatar_url)
e.timestamp = datetime.datetime.utcnow()
question = await ctx.send(embed=e)
await asyncio.sleep(10)
e2 = discord.Embed(color=discord.Color.gold())
e2.title = "New question, new luck."
e2.description = "Test1"
e2.add_field(name="1️⃣", value="02/24/1955")
e2.add_field(name="2️⃣", value="03/24/1955")
e2.add_field(name="3️⃣", value="02/24/1965")
e2.set_footer(text="You have x-x to answer this question.")
e2.timestamp = datetime.datetime.utcnow()
await question.edit(embed=e2)
await asyncio.sleep(10)
e3 = discord.Embed(color=discord.Color.gold())
e3.title = "Test2"
e3.description = "When was Steve Jobs born?"
e3.add_field(name="1️⃣", value="02/24/1955")
e3.add_field(name="2️⃣", value="03/24/1955")
e3.add_field(name="3️⃣", value="02/24/1965")
e3.set_footer(text="You have x-x to answer this question.")
e3.timestamp = datetime.datetime.utcnow()
await question.edit(embed=e3)
await asyncio.sleep(10)
My approach would have been to do it via an enumeration, i.e.
first, second, third = "A", "B", "A" or correct_answers = ["A", "B", "B"] but in both cases it doesn't work. Would I have to go through a list and how exactly do I do that? I also read that you can get the results via an index, but then it fails for me.
In summary:
The first execution of the command should recognize A as correct, then the second time for example B, and the third time for example C.
Using the embed code provided I have used wait_for like my previous example. Still reduces the need for a second command. If you wanted you would have to implement a storage system. I have done the first command as an example. If you wanted to set a limit you can use timeout=seconds in the wait_or
#commands.command()
async def trivia_c(self, ctx):
def check(m):
return m.author == ctx.author and m.channel == ctx.message.channel
e = discord.Embed(color=discord.Color.gold())
e.title = "New question, new luck."
e.description = "**When was Steve Jobs born?**"
e.add_field(name="1️⃣", value="02/24/1955", inline=False)
e.add_field(name="2️⃣", value="03/24/1955", inline=False)
e.add_field(name="3️⃣", value="02/24/1965", inline=False)
e.set_footer(text="You have x-x to answer this question.", icon_url=self.bot.user.avatar_url)
e.timestamp = datetime.datetime.utcnow()
question = await ctx.send(embed=e)
try:
reply = await client.wait_for('message', check=check)
if reply.content == "a":
print("Good")
else:
print("bad")
await reply.delete()
except:
return await question.edit(content="You took too long, so the question is gone.")
await asyncio.sleep(10)
# Next
import random
#commands.command()
async def question(self, ctx):
def check(m):
return m.author == ctx.author and m.channel == ctx.message.channel
question_one = "How many lives do cat's have?"
answers_one = {"9":"a","1":"b","10":"c"}
questions = {question_one:{"9":answers_one}, "Pineapple on pizza?":{"yes":{"yes":"a",
"no":"b"}}}
# get a question
question = random.choice(list(questions.keys()))
data = questions.get(question)
correct_answer = list(data.keys())[0]
answers = list(list(data.values())[0].items())
question_msg = ""
answers_msg = ""
numbers_list = []
answers_list = []
for answer, number in answers:
numbers_list.append(number)
answers_list.append(answer)
while numbers_list != []:
num = random.choice(numbers_list)
ans = random.choice(answers_list)
answers_msg += f"{num}. {ans}\n"
answers_list.remove(ans)
numbers_list.remove(num)
question_msg = f"{question}\nPlease pick one of the following:\n{answers_msg}"
question_sent = await ctx.send(question_msg)
try:
reply = await client.wait_for('message', check=check)
except:
return await question_sent.edit(content="You took too long, so the question is gone.")
await reply.delete()
if reply.content == correct_answer:
await ctx.send("Well done!")
else:
await ctx.send("Nope. How can you get confused!")
This uses wait_for which means you can share the data and not need multiple commands.
This supports the use of multiple questions.
During testing I got:
How many lives do cat's have?
Please pick one of the following:
c. 1
b. 10
a. 9
How many lives do cat's have?
Please pick one of the following:
a. 10
b. 9
c. 1

Discord.py bot clear

Alright so guys i need some help. Basically i am making an discord bot. I'm having problems with clear(purge) command. So this is my code so far:
#client.command(aliases= ['purge','delete'])
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount : int):
if amount == None:
await ctx.channel.purge(limit=1000000)
else:
await ctx.channel.purge(limit=amount)
my problem here is this if amount == None .
Please help me!
Im getting an error that i have missing requied argument...
That's because you're not giving amount the default value None. This is how you should define the function:
#client.command(aliases= ['purge','delete'])
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount=None): # Set default value as None
if amount == None:
await ctx.channel.purge(limit=1000000)
else:
try:
int(amount)
except: # Error handler
await ctx.send('Please enter a valid integer as amount.')
else:
await ctx.channel.purge(limit=amount)
This one is working for me
#client.command()
#has_permissions(manage_messages = True)
async def clear(ctx , amount=5):
await ctx.channel.purge(limit=amount + 1)
I got it from a youtuber channel, you can put the number of the messages u want to clear after the clear command, EX:
-clear 10
Try this:
#client.command(aliases = ['purge', 'delete'])
#commands.has_permissions(manage_messages = True)
async def clear(ctx, amount: int = 1000000):
await ctx.channel.purge(limit = amount)
This should work, as I have a clear command that looks almost exactly like this. The amount param is being converted to an int and if the client doesn't give parameters, the amount will be set at 1000000.
This is the one I'm using atm.
#bot.command(name='clear', help='this command will clear msgs')
async def clear(ctx, amount = 50): # Change amount
if ctx.message.author.id == (YOUR USER ID HERE):
await ctx.channel.purge(limit=amount)
else:
await ctx.channel.send(f"{ctx.author.mention} you are not allowed")
I've just added an 'if' statement for being the only one who can use that command. You can also allow an specific role.
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='>')
#client.event
async def on_ready():
print("Log : "+str(client.user))
#client.command()
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount: int):
await ctx.channel.purge(limit=amount+1)
await ctx.message.delete()
client.run("token")
you can do this:
#client.command(aliases= ['purge','delete'])
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount :int = -1):
if amount == -1:
await ctx.channel.purge(limit=1000000)
else:
await ctx.channel.purge(limit=amount)
I think it should work, if the client doesn't give parameters, the amount will be set at "-1"

Resources