2
votes

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

1

1 Answers

4
votes

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)