What i am specifically looking for is that i want is for the exception to be thrown on ("you must mention someone to x") and for the exception of if the person isn't in the guild to throw that message instead of using the cooldown.
#tasks.loop(count=1)
async def load_interaction_commands(self):
""" Load interaction commands. """
self.bot.interaction_commands = []
cooldown = commands.Cooldown(1, 600, commands.BucketType.user)
mapping = commands.CooldownMapping(cooldown)
for cmd, aliases in COMMANDS.items():
async def interaction_callback(cls, ctx, user: discord.Member):
if not user:
await ctx.send(f"You must mention someone to {ctx.command}.")
elif user == ctx.author:
await ctx.send("You can't {} yourself, silly!".format(ctx.command.name))
elif not discord.utils.find(lambda m: m.id == user.id, ctx.guild.members):
await ctx.send("you cant {} someone not in the server silly!")
else:
await cls.interact(ctx, user)
interaction_callback = commands.command(name=cmd, aliases=aliases)(interaction_callback)
interaction_callback._buckets = mapping
interaction_callback.__commands_cooldown__ = cooldown
interaction_callback.cog = self
self.bot.add_command(interaction_callback)
self.bot.interaction_commands.append(interaction_callback)
Related
sorry that this is probably rather easy to fix (I don't really understand the docs)
But, I want a channel to be opened, so only the user and mods can see it. It will be opened when the user adds a reaction to the message, the reaction will then be deleted (leaving just the bot's reaction)
Currently, my code is:
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
if reaction.emoji == '📩':
if user.channel.id == 850622999577231370:
await message.remove_reaction("📩", user)
overwrites = {
guild.default_role: discord.PermissionOverwrite(read_messages=False),
guild.me: discord.PermissionOverwrite(read_messages=True)
}
n = random.randomint(1, 1000)
await guild.create_text_channel(f'Ticket {n}', overwrites=overwrites, categoty="Tickets")
else:
pass
else:
pass
It doesn't seem to run, since there is no error message, but no channels are created either
A few things I noticed:
random.randomint does not exist, it must be random.randrange.
You didn't define guild in the provided code, we'll just use user.guild instead.
To get the channel we use if reaction.message.channel.id and not if user.channel.id, that makes little sense here.
Here is a possible new code:
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
if reaction.emoji == '📩':
print("Reaction")
if reaction.message.channel.id == Your_Channel_ID:
await reaction.message.remove_reaction("📩", user)
guild = user.guild # We get the guild
overwrites = {
guild.default_role: discord.PermissionOverwrite(read_messages=False),
guild.me: discord.PermissionOverwrite(read_messages=True)
}
n = random.randrange(1, 1000) # We choose a number from randrange 1-1000
await guild.create_text_channel(f'Ticket {n}', overwrites=overwrites, categoty="Tickets")
else:
pass
else:
pass
I am trying to make it where when the user initiates the command $createprofile the bot will dm the user with the questions provided in the list, one after the other then post the answers in an embed to a specified channel. Now I have already built the list, but I am unsure of how to build in asking each question one after another, I am possibly thinking of using asyncio wait_for
import discord
from discord.ext import commands
import platform
import cogs._json
class Profile(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
print("Profile Cog has been loaded\n-----")
# #commands.command(aliases=['pm'])
# async def dm(self, ctx, user: discord.User, *, message=None):
# message = message or "This message is sent via dm"
# await user.send(message)
# await ctx.message.delete()
#commands.command()
async def createprofile(ctx, member: discord.Member = None):
userName = ""
userAge = ""
questions = [
"Please input your name/nickname:",
"Please input your age:"
]
dmChannel = await ctx.author.send(
"You will be receiving two questions. One involving your name and the other your age.")
def check(message):
return message.author == ctx.author and message.channel == dmChannel.channel
async def askQuestion(question):
await ctx.author.send(question)
print("Waiting for reply...")
userReply = await client.wait_for('message', check=check)
print("User replied")
return userReply.content
userName = await askQuestion(questions[0])
userAge = await askQuestion(questions[1])
e = discord.Embed(title=str(userName) + "'s Profile", description=f"""
Age: `{str(userAge)}`
""")
await ctx.send(embed=e)
def setup(bot):
bot.add_cog(Profile(bot))
#client.command()
async def createprofile(self, ctx, member: discord.Member = None):
userName = ""
userAge = ""
questions = [
"Please input your name/nickname:",
"Please input your age:"
]
dmChannel = await ctx.author.send(
"Yo will be receiving two questions. One involving your name and the other your age.")
def check(message):
return message.author == ctx.author and message.channel == dmChannel.channel
async def askQuestion(question):
await ctx.author.send(question)
print("Waiting for reply...")
userReply = await client.wait_for('message', check=check)
print("User replied")
return userReply.content
userName = await askQuestion(questions[0])
userAge = await askQuestion(questions[1])
e = discord.Embed(title=str(userName) + "'s Profile", description=f"""
Age: `{str(userAge)}`
""")
await ctx.send(embed=e)
First, you need to send the user a question, so how you do that is through await ctx.author.send("this is a question"). You then store that message into a variable. You then create a check function that makes sure that the user who replied is in fact the user who sent the $createprofile message in the first place. You will also need to check if the message's channel is the dm channel. So that's where the message you stored earlier takes action. It will make sure that the channel of the message is the same as the channel of the dm message you sent to the user earlier. After that, you create an async function to ask a question. From there on it's pretty straightforward. Feel free to optimize your code using for loops. Hope this helps.
This is my discord.py bot. When I type m!rate (person) It sends me a text like this. However, I don't want the (' and ',) at the beginning and end of the message.
This is my code:
#client.command()
async def rate(ctx, *member):
if len(member) == 0:
await ctx.send("You forgot to mention someone")
else:
value = random.randint(1,10)
await ctx.send(f"I rate {member} {value}/10")
When I change it, the message works but the error doesn't. I can't find any solution.
Using * in a parameter makes the function pass positional arguments into a tuple, hence the brackets. This is usually for when you want to unpack an arbitrary amount of arguments.
To fix it, just remove *, and also add a type for the parameter if you want:
#client.command()
async def rate(ctx, member: discord.Member = None): # setting a default value of None
if not member: # testing to see if the default value is None
await ctx.send("You forgot to mention someone")
else:
value = random.randint(1,10)
await ctx.send(f"I rate {member.mention} {value}/10")
References:
Using * in Python
discord.Member
Member.mention
If you want your bot to mention one person per command :
#client.command()
async def rate(ctx, *member):
if member:
"".join(member)
value = random.randint(1,10)
for user in ctx.guild.members:
if user.name.lower() == member.lower() or user.nick.lower() == member.lower():
await ctx.send(f"I rate {user.mention} {value}/10")
else:
await ctx.send("Member not found!")
else:
await ctx.send("You forgot to mention someone")
If you want your bot to mention multiple people per command :
#client.command()
async def rate(ctx, *members):
if members:
embed = Discord.embed(color = discord.color.blue(), title = "title")
count = 0
for member in members:
value = random.randint(1,10)
for user in ctx.guild.members:
if user.name.lower() == member.lower() or user.nick.lower() == member.lower():
embed.add_field(name = f"{user.mention}", value = f"I rate him {value}/10")
count += 1
if count != 0:
await ctx.send(embed=embed)
else:
await ctx.send("Members not found!")
else:
await ctx.send("You forgot to mention someone")
In my discord bot I have some code that asks the user for input a couple of times in one command, Is there a way to have another bot command when triggered stops the current command or even forces the bot to stop running and restart entirely? Here is some of my smaller code, I would like to keep the same formatting and everything, just a command to break out of that command.
#client.command()
#commands.has_any_role("Betauri Members")
async def wsadd(ctx):
async def get_input_of_type(func):
global sentdex_guild
while True:
try:
msg = await client.wait_for('message', check=check)
return func(msg.content)
except ValueError:
continue
def check(m):
return m.content == m.content and m.channel == channel and m.author == ctx.author
channel = ctx.channel
await channel.send('type your ign, example...')
await channel.send('aaaafireball')
await channel.send('(dont retype $wslist)')
name = await get_input_of_type(str)
name = name+':'
await channel.send('type bs mods, example...')
await channel.send('bs: battery10,delta4,tw1,barrier1')
bs = await get_input_of_type(str)
await channel.send('type first support ship mods, example...')
await channel.send('miner: tw1,genesis1')
sup1 = await get_input_of_type(str)
await channel.send('type second support ship mods, example...')
await channel.send('trans: tw1,dispatch1')
sup2 = await get_input_of_type(str)
You can write your check such that it raises an exception instead of returning a falsy value when it sees certain kinds of messages:
class AbortWait(Exception):
pass
def check(m):
if m.content == 'abort':
raise AbortWait
return m.content == m.content and m.channel == channel and m.author == ctx.author
You can also handle the error in the error handler if you want special behaviour after the command has ended
#wsadd.error
async def wadd_error(ctx, error):
if isinstance(error, commands.CommandInvokeError) and isinstance(error.original, AbortWait):
await ctx.send("Command aborted")
else:
raise error
Hmm ..
What about an if statment after each step to check if the user wants to exit or not ?
Just like :
if(user_input.upper() == "QUIT"):
return
So I have a piece of code and it requires user input multiple times (and what is inputed is not alway the same). Instead of passing the code to everyone in my discord I would like to make it directly into a discord bot so everyone can use it. How do I all the bot to take in a user msg after a code is given
here is an example of kinda what I want:
-.botcalc
--this is discord bot, enter first number:
-1
--enter second number:
-2
--1+2 = 3
There are two ways you could write this command: one is using the "conversation" style in your question
from discord.ext.commands import Bot
bot = Bot("!")
def check(ctx):
return lambda m: m.author == ctx.author and m.channel == ctx.channel
async def get_input_of_type(func, ctx):
while True:
try:
msg = await bot.wait_for('message', check=check(ctx))
return func(msg.content)
except ValueError:
continue
#bot.command()
async def calc(ctx):
await ctx.send("What is the first number?")
firstnum = await get_input_of_type(int, ctx)
await ctx.send("What is the second number?")
secondnum = await get_input_of_type(int, ctx)
await ctx.send(f"{firstnum} + {secondnum} = {firstnum+secondnum}")
The second is to use converters to accept arguments as part of the command invocation
#bot.command()
async def calc(ctx, firstnum: int, secondnum: int):
await ctx.send(f"{firstnum} + {secondnum} = {firstnum+secondnum}")
Using wait_for
async def botcalc(self, ctx):
author = ctx.author
numbers = []
def check(m):
return m.author == author
for _ in ('first', 'second'):
await ctx.send(f"enter {_} number")
num = ""
while not num.isdigit():
num = await client.wait_for('message', check=check)
numbers.append[int(num)]
await channel.send(f'{numbers[0]}+{numbers[1]}={sum{numbers)}')
edit
Added a check