Reputation: 47
I want to set up an embedded message that has emojis reacted on it, where when a user clicks on a certain emoji, it gives them a role. I've been digging to find help everywhere...
I've got the embedded message part, but just don't know how to add the emoji reactions to the embed or have it set to grant a user the role upon click of the emoji.
@client.event
async def on_message(message) :
#ignore this portion
if message.author == client.user:
return
elif message.content.startswith("~ping"):
await client.send_message(message.channe,"Pong!")
#read below this now
elif message.content.startswith("~embed"):
emb = (discord.Embed(title="role Update", description="Use the emotes to role", colour=0x3DF270))
await client.send_message(message.channel, embed=emb)
elif message.content.startswith("~embedroles"):
channel = bot.get_channel('532629344774914069')
role = discord.utils.get(user.server.roles, name="test")
while True:
reaction = await client.wait_for_reaction(emoji='\N{THUMBS UP SIGN}', message=message)
await bot.add_roles(reaction.message.author, role)
I hope this makes sense. Here is an example of what I'm referring to...https://imgur.com/2QYCSAi
Upvotes: 2
Views: 7608
Reputation: 927
First remember that you're limited to 20 reactions per message.
To add a reaction, you have to pass through its Unicode version, or the discord.Emoji
object. As said in the faq, you need to use the Client.add_reaction
, which takes the message and the emoji to react with as arguments.
To get the discord.Message
object, simply assign the sent message to a variable: reacted_message = await client.send_message(channel, embed=embed)
.
You may iterate on a tuple containing the reactions to add (with a simple for loop) to make the bot react to the message.
Instead of using the Client.wait_for_reaction
method, which is useful when you can only react in a limited time, I suggest you use the on_reaction_add
event, which will feedback a discord.Reaction
and the discord.User
whom reacted.
In this event, you need to compare the message which got a reaction, accessible with discord.Reaction.message
with the message you are watching. That's why the message we kept in a variable before should be saved somewhere accessible, such as an attribute of your bot (let's say self.watched_messages
), so you can first check if the message is a "watched one". Instead of using the message object directly, I suggest you use its ID as a key in a dict (self.watched_messages
), the value being another dict: the 'role-giving' reactions (their Unicode value, or ID if customs) and the roleID to give.
If the reacted message ID is in the dict, and if the emoji is in the list indexed by the messageID in the key, then you use Client.add_roles
to add the role to the Member.
As you only get the discord.User
which reacted, you need to get the right discord.Member
to add a role to. You may pass by the discord.Message.server
.
Similarly (keeping the same nested dicts), use the on_reaction_remove
event to remove the role, with Client.remove_roles
.
this is a pseudo-code for what I had in mind
# template of the nested dict:
watched_messages = {
messageID: {
regularEmojiName: roleID,
customEmojiID: roleID
}
}
async def manage_reaction(self, reaction, user, added: bool):
if not reaction.message.id in self.watched_messages:
return
messageID = reaction.message.id
mapping = self.watched_messages[messageID]
if not reaction.emoji in mapping:
# reaction.emoji is str if normal emoji or ID if custom, but we use both as keys in mapping
return
member = discord.utils.get(reaction.message.server.members, id=user.id)
role = discord.utils.get(reaction.message.server.roles, id=mapping[reaction.emoji])
if added:
await client.add_roles(member, role)
else:
await client.remove_roles(member, role)
@client.event
async def on_reaction_add(self, reaction, user):
await self.manage_reactions(reaction, user, True)
@client.event
async def on_reaction_remove(self, reaction, user):
await self.manage_reactions(reaction, user, False)
Upvotes: 5