Esempio n. 1
0
 async def send_embed(channel, header, text):
     """ Sends embed to channel, splitting if necessary """
     if len(text) < 1000:
         embed = discord.Embed(color=color_pick(181, 0, 0))
         embed.add_field(name=header, value=text, inline=False)
         embed.set_footer(
             text=
             "If someone is no longer in your clan, please notify a Chat Mod "
             "to have their Member role removed.",
             icon_url="http://www.mayodev.com/images/dangerbot.png")
         await channel.send(embed=embed)
     else:
         coll = ""
         for line in text.splitlines(keepends=True):
             if len(coll) + len(line) > 1000:
                 embed = discord.Embed(color=color_pick(181, 0, 0))
                 embed.add_field(name=header, value=coll, inline=False)
                 await channel.send(embed=embed)
                 header = "Continued..."
                 coll = ""
             coll += line
         embed = discord.Embed(color=color_pick(181, 0, 0))
         embed.add_field(name=header, value=coll, inline=False)
         embed.set_footer(
             text=
             "If someone is no longer in your clan, please notify a Chat Mod "
             "to have their Member role removed.",
             icon_url="http://www.mayodev.com/images/dangerbot.png")
         await channel.send(embed=embed)
Esempio n. 2
0
 async def elder(self, ctx, command: str = "help"):
     """Help menu for elder staff"""
     embed = discord.Embed(title="Reddit Oak Elder Help Menu",
                           description="All the elder commands you need but can't remember how to use!",
                           color=color_pick(66, 134, 244))
     embed.add_field(name="Commands:", value="-----------", inline=True)
     if command in ["help", "role"]:
         role = ("Adds the specified role to the specified user if they do not have it. "
                 "Removes the role if they already have it.")
         embed.add_field(name="/role <@discord mention> <discord role>", value=role, inline=False)
     if command in ["help", "warn"]:
         warn_list = "Lists all strikes for all users. Sorted by user (alphabetically)."
         embed.add_field(name="/warn", value=warn_list, inline=False)
         warn_add = ("Adds a strike to the specified player with the specified reason. The bot will "
                     "respond with a list of all strikes for that player. A DM will be sent to the player "
                     "so they know that they have received a warning.")
         embed.add_field(name="/warn <in-game name> <reason for warning>", value=warn_add, inline=False)
         warn_remove = ("Removes the specified warning (warning ID). You will need to do /warn list "
                        "first to obtain the warning ID.")
         embed.add_field(name="/warn remove <warning ID>", value=warn_remove, inline=False)
     if command in ["help", "kick"]:
         kick = ('Removes specified player from the Oak Table adding the reason you supply to the notes. '
                 'Removes the Member role from their Discord account. For players with spaces in '
                 'their name, "user quotes".')
         embed.add_field(name="/kick <in-game name> <reason for kick>", value=kick, inline=False)
     if command in ["help", "ban"]:
         ban = ("Removes specified player from the Oak Table adding the reason you "
                "supply and flags them as a permanent ban. Kicks the player from the Discord server. "
                "For players with spaces in their name, 'use quotes'.")
         embed.add_field(name="/ban <in-game name> <reason for ban>", value=ban, inline=False)
     if command in ["help", "unconfirmed"]:
         un_list = ("Lists all players who have not yet confirmed the rules. "
                    "If they have been in the clan for more than 2 days, you will see a :boot:")
         embed.add_field(name="/unconfirmed", value=un_list, inline=False)
         un_kick = "Move specified player to No Confirmation."
         embed.add_field(name="/unconfirmed kick <in-game name>", value=un_kick, inline=False)
         un_move = ("Move specified player to Regular Member "
                    "(if they failed the quiz or didn't move for some other reason.")
         embed.add_field(name="/unconfirmed move <in-game name>", value=un_move, inline=False)
     await ctx.send(embed=embed)
     self.bot.logger.info(f"{ctx.command} by {ctx.author} in {ctx.channel} | Request: {command}")
Esempio n. 3
0
 async def warn(self, ctx, player: str = None, *, warning=None):
     """Command to add warnings for players
     /warn list (or just /warn) will show a list of all warnings
     To add a warning, use:
     /warn TubaKid This is a warning
     /warn #RVP02LQU This is also a warning
     For names with spaces, use quotes:
     /warn "Professor Mahon" This is another warning
     To remove a warning, request the list first to obtain the warning ID.
     /warn remove #
     """
     conn = self.bot.pool
     if authorized(ctx.author.roles) or ctx.author.id == 251150854571163648:
         if player is None:
             sql = ("SELECT COUNT(strike_num) AS num_warnings, player_name "
                    "FROM oak_warn_list "
                    "GROUP BY player_name "
                    "ORDER BY player_name")
             strikes = await conn.fetch(sql)
             embed = discord.Embed(title="Reddit Oak Warning Count",
                                   description="All warnings expire after 60 days.",
                                   color=color_pick(181, 0, 0))
             embed_text = ""
             for row in strikes:
                 embed_text += f"{row['player_name']} - {row['num_warnings']} warnings\n"
             embed.add_field(name="Warning Counts", value=embed_text)
             return await ctx.send(embed=embed)
         if player == "list":
             sql = ("SELECT player_name, strike_num || '. ' || warning || ' (' || DATE(timestamp) || ') [' "
                    "|| warning_id || ']' AS warning_text "
                    "FROM oak_warn_list "
                    "ORDER BY player_name, strike_num")
             strike_list = await conn.fetch(sql)
             strikes = {}
             name = ""
             for strike in strike_list:
                 if strike['player_name'] != name:
                     name = strike['player_name']
                     strikes[name] = ""
                 strikes[name] += strike['warning_text'] + "\n"
             print(strikes)
             embed = discord.Embed(title="Reddit Oak Watchlist",
                                   description="All warnings expire after 60 days.",
                                   color=color_pick(181, 0, 0))
             for name, strike in strikes.items():
                 embed.add_field(name=name, value=strike, inline=False)
             embed.set_footer(icon_url=("https://openclipart.org/image/300px/svg_to_png/109/"
                                        "molumen-red-round-error-warning-icon.png"),
                              text="To remove a strike, use /warn remove <Warning ID>")
             self.bot.logger.debug(f"{ctx.command} by {ctx.author} in {ctx.channel} | Request: List warnings")
             return await ctx.send(embed=embed)
         elif player == "remove":
             warning_id = warning
             sql = ("SELECT strike_num, player_name, timestamp, warning, warning_id "
                    "FROM oak_warn_list "
                    "WHERE warning_id = $1")
             fetch = await conn.fetchrow(sql, int(warning_id))
             if fetch is None:
                 return await ctx.send("No warning exists with that ID.  Please check the ID and try again.")
             response = await ctx.prompt(f"Are you sure you want to remove\n{fetch['warning']}\n"
                                         f"from {fetch['player_name']}?")
             if not response:
                 return await ctx.send(content="Removal cancelled.  Maybe try again later if you feel up to it.")
             sent_msg = await ctx.send(content="Removal in progress...")
             sql = "DELETE FROM oak_warnings WHERE warning_id = $1"
             await conn.execute(sql, int(warning_id))
             self.bot.logger.debug(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                   f"Request: Removal of {fetch['warning']} for {fetch['player_name']}")
             await sent_msg.edit(content=f"Warning **{fetch['warning']}** "
                                         f"removed for **{fetch['player_name']}**.")
         else:
             # add a player warning
             if player.startswith("#"):
                 member = await self.bot.coc.get_player(player)
             else:
                 clan = await self.bot.coc.get_clan(clans['Reddit Oak'])
                 member = clan.get_member_by(name=player)
                 if not member:
                     clan = await self.bot.coc.get_clan(clans['Reddit Quercus'])
                     member = clan.get_member_by(name=player)
             if not member:
                 self.bot.logger.warning(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                         f"Problem: {player} not found in Clash API | Warning: {warning}")
                 return await ctx.send("You have provided an invalid player name.  Please try again.")
             # Everything looks good, let's add to the database
             sql = ("INSERT INTO oak_warnings (player_tag, timestamp, warning) "
                    "VALUES ($1, $2, $3)")
             await conn.execute(sql, member.tag[1:], datetime.utcnow(), warning)
             sql = ("SELECT player_name, strike_num || '. ' || warning || ' (' || "
                    "DATE(timestamp) || ')' AS warning_text "
                    "FROM oak_warn_list WHERE player_name = $1 "
                    "ORDER BY strike_num")
             strikes = await conn.fetch(sql, member.name)
             discord_id = await self.bot.links.get_link(member.tag)
             user = ctx.guild.get_member(discord_id)
             header = f"**Warnings for {member.name}**"
             content = ""
             for strike in strikes:
                 content += strike['warning_text'] + "\n"
             await ctx.send(header + "\n" + content)
             await user.send("New warning added:\n" + content)
             self.bot.logger.debug(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                   f"Request: {member.name} warned for {warning}")
     else:
         self.bot.logger.warning(f"User not authorized - "
                                 f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                 f"Request: Warning for {player} for {warning}")
         await ctx.send("Wait a minute punk! You aren't allowed to use that command")
Esempio n. 4
0
 async def player(self, ctx, *, player: PlayerConverter = None):
     """Provide details on the specified player"""
     if not player:
         self.bot.logger.warning(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                 f"Problem: No valid player name or tag was provided.")
         return await ctx.send(f"{emojis['other']['redx']} You must provide a valid in-game name or tag for this "
                               f"command. Try `/player TubaKid`")
     # pull non-in-game stats from db
     with Sql() as cursor:
         sql = (f"SELECT tag, numWars, avgStars, warStats, joinDate, slackId "
                f"FROM coc_oak_players "
                f"WHERE tag = ?")
         cursor.execute(sql, player.tag[1:])
         oak_stats = cursor.fetchone()
     try:
         if not oak_stats:
             self.bot.logger.warning(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                     f"Problem: {player.name} not found in SQL database")
             return await ctx.send(f"{emojis['other']['redx']} The player you provided was not found in the "
                                   f"database. Please try again.")
     except:
         self.bot.logger.error(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                               f"Unknown error has occurred")
         return await ctx.send(f"{emojis['other']['redx']} Something has gone horribly wrong. "
                               f"<@251150854571163648> I was trying to look up {player.name} "
                               f"but the world conspired against me.")
     # retrieve player info from coc.py
     player_tag = f"#{oak_stats.tag}"
     player = await self.bot.coc.get_player(player_tag)
     troop_levels = builder_levels = spell_levels = hero_levels = hero_pets_levels = builder_hero = \
         sm_levels = super_troop_levels = ""
     sm_troops = enums.SIEGE_MACHINE_ORDER
     super_troops = enums.SUPER_TROOP_ORDER
     count = 0
     for troop in player.home_troops:
         if troop.name in super_troops:
             # We're ignoring super troops at this time
             continue
         if troop.name not in sm_troops:
             count += 1
             if troop.name == "Minion":
                 count = 1
                 if troop_levels[-2:] == "\n":
                     troop_levels += "\n"
                 else:
                     troop_levels += "\n\n"
             if troop.name not in enums.HERO_PETS_ORDER:
                 troop_levels += f"{emojis['troops'][troop.name]}{str(troop.level)} "
             if count % 6 == 0:
                 troop_levels += "\n"
         else:
             sm_levels += f"{emojis['siege'][troop.name]}{str(troop.level)} "
     count = 0
     for spell in player.spells:
         count += 1
         if spell.name == "Poison Spell" and spell_levels[-2:] != "\n":
             spell_levels += "\n"
             count = 1
         spell_levels += f"{emojis['spells'][spell.name]}{str(spell.level)} "
     count = 0
     # Handle Super Troops
     for troop in player.home_troops:
         if troop.name in super_troops:
             count += 1
             if troop.is_active:
                 super_troop_levels += f"{emojis['super_troops_active'][troop.name]}{str(troop.level)} "
             else:
                 super_troop_levels += f"{emojis['super_troops'][troop.name]}{str(troop.level)} "
             if count % 6 == 0:
                 super_troop_levels += "\n"
     count = 0
     for troop in player.builder_troops:
         count += 1
         builder_levels += f"{emojis['build_troops'][troop.name]}{str(troop.level)} "
         if count % 6 == 0:
             builder_levels += "\n"
     # Test for number of heroes
     if len(player.heroes) > 0:
         for hero in player.heroes:
             if hero.name != "Battle Machine":
                 hero_levels += f"{emojis['heroes'][hero.name]}{str(hero.level)} "
             else:
                 builder_hero = f"{emojis['heroes'][hero.name]}{str(hero.level)}"
         for troop in player.home_troops:
             if troop.name in enums.HERO_PETS_ORDER:
                 hero_pets_levels += f"{emojis['hero_pets'][troop.name]}{str(troop.level)} "
     embed = discord.Embed(title=f"{emojis['league'][leagues_to_emoji[player.league.name]]} "
                                 f"{player.name} "
                                 f"({player.tag})",
                           color=color_pick(226, 226, 26))
     embed.add_field(name="Town Hall",
                     value=f"{emojis['th_icon'][player.town_hall]} {str(player.town_hall)}",
                     inline=True)
     embed.add_field(name="Trophies", value=player.trophies, inline=True)
     embed.add_field(name="Best Trophies", value=player.best_trophies, inline=True)
     embed.add_field(name="War Stars", value=player.war_stars, inline=True)
     embed.add_field(name="Attack Wins", value=player.attack_wins, inline=True)
     embed.add_field(name="Defense Wins", value=player.defense_wins, inline=True)
     embed.add_field(name="Wars in Oak", value=oak_stats.numWars, inline=True)
     embed.add_field(name="Avg. Stars per War", value=str(round(oak_stats.avgStars, 2)), inline=True)
     embed.add_field(name="This Season", value=oak_stats.warStats, inline=False)
     embed.add_field(name="Troop Levels", value=troop_levels, inline=False)
     if super_troop_levels != "":
         embed.add_field(name="Super Troops", value=super_troop_levels, inline=False)
     if sm_levels != "":
         embed.add_field(name="Siege Machines", value=sm_levels, inline=False)
     embed.add_field(name="Spell Levels", value=spell_levels, inline=False)
     if hero_levels != "":
         embed.add_field(name="Heroes", value=hero_levels, inline=False)
     if hero_pets_levels != "":
         embed.add_field(name="Hero Pets", value=hero_pets_levels, inline=False)
     embed.add_field(name="Builder Hall Level",
                     value=f"{emojis['bh_icon'][player.builder_hall]} {str(player.builder_hall)}",
                     inline=False)
     embed.add_field(name="Versus Trophies", value=str(player.versus_trophies), inline=True)
     embed.add_field(name="Versus Battle Wins", value=str(player.versus_attack_wins), inline=True)
     embed.add_field(name="Best Versus Trophies", value=str(player.best_versus_trophies), inline=True)
     embed.add_field(name="Troop Levels", value=builder_levels, inline=False)
     if builder_hero != "":
         embed.add_field(name="Hero", value=builder_hero, inline=False)
     embed.set_footer(icon_url=player.clan.badge.url,
                      text=f"Member of Reddit Oak since {oak_stats.joinDate.strftime('%e %B, %Y')}")
     self.bot.logger.debug(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                           f"Request complete: /player {player.name}")
     await ctx.send(embed=embed)
Esempio n. 5
0
    async def siege_request(self, ctx, *, siege_req: str = "help"):
        """- For requesting siege machines

        Options:
         - ww, wall wrecker
         - air1, blimp, battle blimp, bb
         - air2, stone, slam, slammer, stone slammer
         - barracks, sb

         **Example:**
         /siege wall wrecker
         /siege blimp
         /siege Stone Slammer
         /siege barracks
         """
        user_id = ctx.author.id
        if siege_req == "help":
            embed = discord.Embed(title="The Arborist by Reddit Oak", color=color_pick(15, 250, 15))
            embed.add_field(name="Commands:", value="-----------", inline=True)
            siege = ("Posts request for the specified siege machine in Discord and tags those players that can donate."
                     "\n**ground**: Wall Wrecker"
                     "\n**blimp**: Battle Blimp"
                     "\n**slammer**: Stone Slammer"
                     "\n**barracks**: Siege Barracks")
            embed.add_field(name="/siege <siege type>", value=siege, inline=False)
            embed.set_footer(icon_url="https://openclipart.org/image/300px/svg_to_png/122449/1298569779.png",
                             text="The Arborist proudly maintained by TubaKid.")
            await ctx.send(embed=embed)
            return
        if siege_req in ["ww", "wall wrecker"]:
            siege_name = "Wall Wrecker"
            thumb = "https://coc.guide/static/imgs/troop/siege-machine-ram.png"
        elif siege_req in ["blimp", "air1", "bb", "battle blimp"]:
            siege_name = "Battle Blimp"
            thumb = "https://coc.guide/static/imgs/troop/siege-machine-flyer.png"
        elif siege_req in ["stone", "slammer", "slam", "air2", "stone slammer"]:
            siege_name = "Stone Slammer"
            thumb = "https://coc.guide/static/imgs/troop/siege-bowler-balloon.png"
        elif siege_req in ["barracks", "sb", "seige barracks", "baracks"]:
            siege_name = "Siege Barracks"
            thumb = "https://coc.guide/static/imgs/troop/siege-machine-carrier.png"
        else:
            await ctx.send("You have provided an invalid siege machine type. "
                           "Please specify `ground`, `blimp`, `slammer`, or `barracks`")
            return
        sent_msg = await ctx.send(f"One moment while I check to see who has those.")
        donors = []
        requestor = None
        # get requestor player tag from Discord ID
        clan = await self.bot.coc.get_clan("#CVCJR89")
        requestor_tag = await self.bot.links.get_linked_players(user_id)
        # Remove any links for player tags that aren't currently in Oak
        if len(requestor_tag) > 1:
            clan_tags = [x.tag for x in clan.members]
            for tag in requestor_tag:
                if tag not in clan_tags:
                    requestor_tag.remove(tag)
        # If still more than one, prompt user for correct player
        if len(requestor_tag) > 1:
            prompt_text = "You have more than one player in Reddit Oak. Please select the correct player:"
            counter = 1
            for tag in requestor_tag:
                player = await self.bot.coc.get_player(tag)
                prompt_text += f"\n{counter}. {player.name} ({player.tag})"
            prompt = ctx.prompt(prompt_text, additional_options=len(requestor_tag))
            requestor_tag = requestor_tag[prompt - 1]
        # find oak players with the requested siege machine
        async for player in clan.get_detailed_members():
            if siege_name in [troop.name for troop in player.siege_machines]:
                discord_id = await self.bot.links.get_discord_links(player.tag)
                donors.append(f"{player.name}: <@{discord_id}>")
            if requestor_tag == player.tag:
                requestor = player.name
        if not requestor:
            requestor = ctx.author.name
        await sent_msg.delete()
        embed = discord.Embed(title=f"{siege_name} Request",
                              description=f"{requestor} has requested a {siege_name}",
                              color=0xb5000)
        embed.set_footer(icon_url=thumb, text="Remember to select your siege machine when you attack!")
        content = "**Potential donors include:**\n"
        content += "\n".join(donors)
        await ctx.send(embed=embed)
        await ctx.send(content)
Esempio n. 6
0
    async def help(self, ctx, command: str = "all"):
        """ Welcome to The Arborist"""
        desc = """All commands must begin with a slash.

        You can type /help <command> to display only the help for that command."""
        # ignore requests for help with the war command
        if command == "war":
            return
        # respond if help is requested for a command that does not exist
        if command not in ["all", "siege", "player", "elder"]:
            self.bot.logger.warning(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                                    f"Problem: /help {command} - command does not exist")
            await ctx.send(f"{emojis['other']['redx']} You have provided a command that does not exist. "
                           f"Perhaps try /help to see all commands.")
            return
        embed = discord.Embed(title="The Arborist by Reddit Oak", description=desc, color=color_pick(15, 250, 15))
        embed.add_field(name="Commands:", value="-----------", inline=True)
        if command in ["all", "siege"]:
            siege = ("Posts request for the specified siege machine in Discord and tags those players that can donate."
                     "\n**ground**: Wall Wrecker"
                     "\n**blimp**: Battle Blimp"
                     "\n**slammer**: Stone Slammer"
                     "\n**barracks**: Siege Barracks")
            embed.add_field(name="/siege <siege type>", value=siege, inline=False)
        if command in ["all", "player"]:
            player = ("Display vital statistics on the requested player. This includes information "
                      "on in game stats as well as stats while in Reddit Oak.")
            embed.add_field(name="/player <in game name>", value=player, inline=False)
        if command in ["all", "avatar"]:
            avatar = "Provides an enlarged version of the specified player's avatar."
            embed.add_field(name="/avatar <Discord Mention or ID>", value=avatar, inline=False)
        if command == "elder":
            elder = "To display help for elder commands, please type /elder."
            embed.add_field(name="/elder", value=elder, inline=False)
        embed.set_footer(icon_url="https://openclipart.org/image/300px/svg_to_png/122449/1298569779.png",
                         text="The Arborist proudly maintained by TubaKid.")
        self.bot.logger.debug(f"{ctx.command} by {ctx.author} in {ctx.channel} | "
                              f"Request complete: /help {command}")
        await ctx.send(embed=embed)