Ejemplo n.º 1
0
    async def on_command_error(self, ctx, error):
        """ Send help message when a mis-entered command is received. """
        if type(error) is commands.CommandNotFound:
            # Get Levenshtein distance from commands
            in_cmd = ctx.invoked_with
            bot_cmds = list(self.bot.commands)
            lev_dists = [
                lev.distance(in_cmd, str(cmd)) /
                max(len(in_cmd), len(str(cmd))) for cmd in bot_cmds
            ]
            lev_min = min(lev_dists)

            # Prep help message title
            embed_title = translate('command-not-valid', ctx.message.content)
            prefixes = self.bot.command_prefix
            prefix = prefixes[
                0] if prefixes is not str else prefixes  # Prefix can be string or iterable of strings

            # Make suggestion if lowest Levenshtein distance is under threshold
            if lev_min <= 0.5:
                embed_title += translate(
                    'did-you-mean'
                ) + f' `{prefix}{bot_cmds[lev_dists.index(lev_min)]}`?'
            else:
                embed_title += translate('use-help', prefix)

            embed = self.bot.embed_template(title=embed_title)
            await ctx.send(embed=embed)
Ejemplo n.º 2
0
    async def captains(self, ctx, method=None):
        """ Set or display the method by which captains are selected. """
        if not await self.bot.is_pug_channel(ctx):
            return

        guild_data = await self.bot.db_helper.get_pug(ctx.channel.category_id)
        captain_method = guild_data['captain_method']
        valid_methods = ['volunteer', 'rank', 'random']

        if method is None:
            title = translate('captains-method', captain_method)
        else:
            method = method.lower()

            if method == captain_method:
                title = translate('captains-method-already', captain_method)
            elif method in valid_methods:
                title = translate('set-captains-method', method)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    captain_method=method)
            else:
                title = translate('captains-valid-method', valid_methods[0],
                                  valid_methods[1], valid_methods[2])

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)
Ejemplo n.º 3
0
    async def maps(self, ctx, method=None):
        """ Set or display the method by which the teams are created. """
        if not await self.bot.is_pug_channel(ctx):
            return

        map_method = await self.bot.get_pug_data(ctx.channel.category,
                                                 'map_method')
        valid_methods = ['captains', 'vote', 'random']

        if method is None:
            title = translate('map-method', map_method)
        else:
            method = method.lower()

            if method == map_method:
                title = translate('map-method-already', map_method)
            elif method in valid_methods:
                title = translate('set-map-method', method)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    map_method=method)
            else:
                title = translate('map-valid-method', valid_methods[0],
                                  valid_methods[1], valid_methods[2])

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)
Ejemplo n.º 4
0
    async def link(self, ctx):
        """ Link a player by sending them a link to sign in with steam on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return

        is_linked = await self.bot.api_helper.is_linked(ctx.author.id)

        if is_linked:
            player = await self.bot.api_helper.get_player(ctx.author.id)
            title = translate('already-linked', player.steam_profile)
        else:
            link = await self.bot.api_helper.generate_link_url(ctx.author.id)

            if link:
                # Send the author a DM containing this link
                try:
                    await ctx.author.send(translate('dm-link', link))
                    title = translate('link-sent')
                except:
                    title = translate('blocked-dm')
            else:
                title = translate('unknown-error')

        embed = self.bot.embed_template(description=title)
        await ctx.send(content=ctx.author.mention, embed=embed)
Ejemplo n.º 5
0
 def _vote_embed(self):
     embed = self.bot.embed_template(title=translate('vote-map-started'))
     str_value = '--------------------\n'
     str_value += '\n'.join(
         f'{EMOJI_NUMBERS[self.map_votes[m.emoji]]} {m.emoji} {m.name} '
         f'{":small_orange_diamond:" if self.map_votes[m.emoji] == max(self.map_votes.values()) and self.map_votes[m.emoji] != 0 else ""} '
         for m in self.map_pool)
     embed.add_field(name=f':repeat_one: :map: __{translate("maps")}__',
                     value=str_value)
     embed.set_footer(text=translate('vote-map-footer'))
     return embed
Ejemplo n.º 6
0
 def _vote_embed(self):
     embed = self.bot.embed_template(
         title='Captains vote for number of maps')
     str_value = '------------\n'
     str_value += '\n'.join(
         f'{num}  Bo{self.numbers.index(num) + 1}'
         f'{":small_orange_diamond:" if self.num_votes[num] == max(self.num_votes.values()) and self.num_votes[num] != 0 else ""} '
         for num in self.numbers)
     embed.add_field(name=f':repeat_one:  __' + translate("match-type") +
                     '__',
                     value=str_value)
     embed.set_footer(text=translate('vote-match-type-footer'))
     return embed
Ejemplo n.º 7
0
    async def forcelink(self, ctx, *args):
        """ Force link player with steam on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return
        print(int(args[1]), type(int(args[1])))
        try:
            user = ctx.message.mentions[0]
        except IndexError:
            title = f"{translate('invalid-usage')}: `{self.bot.command_prefix[0]}forcelink <mention> <Steam64 ID>`"
        else:
            link = await self.bot.api_helper.force_link_discord(
                user.id, args[1])

            if not link:
                title = 'Sorry! Steam ID is already linked with another discord'
            else:
                title = translate('force-linked', user.display_name, args[1])
                role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                      'pug_role')
                role = ctx.guild.get_role(role_id)
                await user.add_roles(role)
                await self.bot.api_helper.update_discord_name(user)

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)
Ejemplo n.º 8
0
    async def autobalance_teams(self, members):
        """ Balance teams based on players' RankMe score. """
        # Only balance teams with even amounts of players
        if len(members) % 2 != 0:
            raise ValueError(translate('members-must-even'))

        # Get players and sort by RankMe score
        members_dict = dict(
            zip(
                await self.bot.api_helper.get_players(
                    [member.id for member in members]), members))
        players = list(members_dict.keys())
        players.sort(key=lambda x: x.score)

        # Balance teams
        team_size = len(players) // 2
        team_one = [players.pop()]
        team_two = [players.pop()]

        while players:
            if len(team_one) >= team_size:
                team_two.append(players.pop())
            elif len(team_two) >= team_size:
                team_one.append(players.pop())
            elif sum(p.score for p in team_one) < sum(p.score
                                                      for p in team_two):
                team_one.append(players.pop())
            else:
                team_two.append(players.pop())

        return list(map(members_dict.get,
                        team_one)), list(map(members_dict.get, team_two))
Ejemplo n.º 9
0
    async def _process_ban(self, reaction, member):
        """ Handler function for map ban reactions. """
        # Check that reaction is on this message
        if reaction.message.id != self.id or member == self.author:
            return

        if member not in self.captains or str(reaction) not in [
                m for m in self.maps_left
        ] or member != self._active_picker:
            await self.remove_reaction(reaction, member)
            return
        # Ban map if the emoji is valid
        try:
            map_ban = self.maps_left.pop(str(reaction))
        except KeyError:
            return

        self.ban_number += 1
        # Clear banned map reaction
        await self.clear_reaction(map_ban.emoji)
        # Edit message
        embed = self._veto_embed(
            translate('user-banned-map', member.display_name, map_ban.name))
        await self.edit(embed=embed)

        # Check if the veto is over
        if len(self.maps_left) == self.num_maps:
            if self.future is not None:
                self.future.set_result(None)
Ejemplo n.º 10
0
    async def stats(self, ctx):
        """ Send an embed containing stats data parsed from the player object returned from the API. """
        if not await self.bot.is_pug_channel(ctx):
            return

        try:
            user = ctx.message.mentions[0]
        except IndexError:
            user = ctx.author

        player = await self.bot.api_helper.get_player(user.id)

        if player:
            win_percent_str = f'{player.win_percent * 100:.2f}%'
            hs_percent_str = f'{player.hs_percent * 100:.2f}%'
            fb_percent_str = f'{player.first_blood_rate * 100:.2f}%'
            description = '```ml\n' \
                          f' {translate("rank-score")}:      {player.score:>6} \n' \
                          f' {translate("matches-played")}:    {player.matches_played:>6} \n' \
                          f' {translate("win-percentage")}:    {win_percent_str:>6} \n' \
                          f' {translate("kd-ratio")}:          {player.kd_ratio:>6.2f} \n' \
                          f' {translate("adr")}:               {player.adr:>6.2f} \n' \
                          f' {translate("hs-percentage")}:     {hs_percent_str:>6} \n' \
                          f' {translate("first-blood-rate")}:  {fb_percent_str:>6} ' \
                          '```'
            embed = self.bot.embed_template(description=description)
            embed.set_author(name=user.display_name,
                             url=player.league_profile,
                             icon_url=user.avatar_url_as(size=128))
        else:
            title = translate("cannot-get-stats", ctx.author.display_name)
            embed = self.bot.embed_template(title=title)

        await ctx.send(embed=embed)
Ejemplo n.º 11
0
    async def check(self, ctx):
        if not await self.bot.is_pug_channel(ctx):
            return

        if not await self.bot.api_helper.is_linked(ctx.author.id):
            msg = translate('discord-not-linked')
        else:
            role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                  'pug_role')
            role = ctx.guild.get_role(role_id)
            await ctx.author.add_roles(role)
            await self.bot.api_helper.update_discord_name(ctx.author)
            msg = translate('discord-get-role')

        embed = self.bot.embed_template(description=msg, color=self.bot.color)
        await ctx.send(content=ctx.author.mention, embed=embed)
Ejemplo n.º 12
0
    async def empty(self, ctx):
        """ Reset the pug's queue list to empty. """
        if not await self.bot.is_pug_channel(ctx):
            return

        self.queue_cog.block_lobby[ctx.channel.category] = True
        await self.bot.db_helper.delete_all_queued_users(
            ctx.channel.category.id)
        msg = translate('queue-emptied')
        embed = await self.queue_cog.queue_embed(ctx.channel.category, msg)

        lobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                               'voice_lobby')
        prelobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                                  'voice_prelobby')
        lobby = ctx.bot.get_channel(lobby_id)
        prelobby = ctx.bot.get_channel(prelobby_id)

        for player in lobby.members:
            await player.move_to(prelobby)

        self.queue_cog.block_lobby[ctx.channel.category] = False
        _embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=_embed)
        # Update queue display message
        await self.queue_cog.update_last_msg(ctx.channel.category, embed)
Ejemplo n.º 13
0
    def _ready_embed(self):
        """ Generate the menu embed based on the current ready status of players. """
        str_value = ''
        description = translate('react-ready', '✅')
        embed = self.bot.embed_template(title=translate('queue-filled'),
                                        description=description)

        for num, member in enumerate(self.members, start=1):
            if member not in self.reactors:
                str_value += f':heavy_multiplication_x:  {num}. [{member.display_name}]({self.players[num-1].league_profile})\n '
            else:
                str_value += f'✅  {num}. [{member.display_name}]({self.players[num-1].league_profile})\n '

        embed.add_field(name=f":hourglass: __{translate('player')}__",
                        value='-------------------\n' + str_value)
        return embed
Ejemplo n.º 14
0
    async def veto(self, pool, captain_1, captain_2, num_maps):
        """"""
        # Initialize veto
        self.captains = [captain_1, captain_2]
        self.map_pool = pool
        self.maps_left = {m.emoji: m for m in self.map_pool}
        self.ban_number = 0
        self.num_maps = num_maps

        if len(self.map_pool) % 2 == 0:
            self.captains.reverse()

        # Edit input message and add emoji button reactions
        await self.edit(embed=self._veto_embed(translate('map-bans-begun')))

        awaitables = [self.add_reaction(m.emoji) for m in self.map_pool]
        await asyncio.gather(*awaitables, loop=self.bot.loop)

        # Add listener handlers and wait until there are no maps left to ban
        self.future = self.bot.loop.create_future()
        self.bot.add_listener(self._process_ban, name='on_reaction_add')
        await asyncio.wait_for(self.future, 600)
        self.bot.remove_listener(self._process_ban, name='on_reaction_add')
        await self.clear_reactions()

        picked_maps = list(self.maps_left.values())
        shuffle(picked_maps)

        return picked_maps
Ejemplo n.º 15
0
 async def config_error(self, ctx, error):
     """ Respond to a permissions error with an explanation message. """
     if isinstance(error, commands.MissingPermissions):
         await ctx.trigger_typing()
         missing_perm = error.missing_perms[0].replace('_', ' ')
         embed = self.bot.embed_template(
             title=translate('required-perm', missing_perm))
         await ctx.send(embed=embed)
Ejemplo n.º 16
0
    async def cap(self, ctx, *args):
        """ Set the queue capacity. """
        if not await self.bot.is_pug_channel(ctx):
            return

        capacity = await self.bot.get_pug_data(ctx.channel.category,
                                               'capacity')

        try:
            new_cap = int(args[0])
        except (IndexError, ValueError):
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}cap <number>`'
        else:
            if new_cap == capacity:
                msg = translate('capacity-already', capacity)
            elif new_cap < 2 or new_cap > 100:
                msg = translate('capacity-out-range')
            else:
                self.queue_cog.block_lobby[ctx.channel.category] = True
                await self.bot.db_helper.delete_all_queued_users(
                    ctx.channel.category_id)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    capacity=new_cap)
                embed = await self.queue_cog.queue_embed(
                    ctx.channel.category, translate('queue-emptied'))
                embed.set_footer(text=translate('queue-emptied-footer'))
                await self.queue_cog.update_last_msg(ctx.channel.category,
                                                     embed)
                msg = translate('set-capacity', new_cap)

                lobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                                       'voice_lobby')
                prelobby_id = await self.bot.get_pug_data(
                    ctx.channel.category, 'voice_prelobby')
                lobby = ctx.bot.get_channel(lobby_id)
                prelobby = ctx.bot.get_channel(prelobby_id)

                for player in lobby.members:
                    await player.move_to(prelobby)

                self.queue_cog.block_lobby[ctx.channel.category] = False
                await lobby.edit(user_limit=new_cap)

        await ctx.send(embed=self.bot.embed_template(title=msg))
Ejemplo n.º 17
0
    async def end(self, ctx, *args):
        """ Force end a match. """
        if not await self.bot.is_pug_channel(ctx):
            return

        if len(args) == 0:
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}end <Match ID>`'
        else:
            matches = await self.bot.api_helper.matches_status()
            if args[0] in matches:
                if await self.bot.api_helper.end_match(args[0]):
                    msg = translate("match-cancelled", args[0])
                else:
                    msg = translate('match-already-over', args[0])
            else:
                msg = translate("invalid-match-id")

        embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=embed)
Ejemplo n.º 18
0
    async def leaders(self, ctx):
        """ Send an embed containing the leaderboard data parsed from the player objects returned from the API. """
        if not await self.bot.is_pug_channel(ctx):
            return

        num = 5  # Easily modfiy the number of players on the leaderboard
        guild_players = await self.bot.api_helper.get_players(
            [user.id for user in ctx.guild.members])

        if len(guild_players) == 0:
            embed = self.bot.embed_template(title=translate("nobody-ranked"))
            await ctx.send(embed=embed)

        guild_players.sort(key=lambda u: (u.score, u.matches_played),
                           reverse=True)

        # Select the top players only
        if len(guild_players) > num:
            guild_players = guild_players[:num]

        # Generate leaderboard text
        data = [
            ['Player'] + [
                ctx.guild.get_member(player.discord).display_name
                for player in guild_players
            ], ['Score'] + [str(player.score) for player in guild_players],
            ['Winrate'] +
            [f'{player.win_percent * 100:.2f}%' for player in guild_players],
            ['Played'] +
            [str(player.matches_played) for player in guild_players]
        ]
        data[0] = [
            name if len(name) < 12 else name[:9] + '...' for name in data[0]
        ]  # Shorten long names
        widths = list(map(lambda x: len(max(x, key=len)), data))
        aligns = ['left', 'right', 'right', 'right']
        z = zip(data, widths, aligns)
        formatted_data = [
            list(map(lambda x: align_text(x, width, align), col))
            for col, width, align in z
        ]
        formatted_data = list(map(
            list, zip(*formatted_data)))  # Transpose list for .format() string
        description = '```ml\n    {}  {}  {}  {} \n'.format(*formatted_data[0])

        for rank, player_row in enumerate(formatted_data[1:], start=1):
            description += ' {}. {}  {}  {}  {} \n'.format(rank, *player_row)

        description += '```'

        # Send leaderboard
        title = f'__{translate("server-leaderboard")}__'
        embed = self.bot.embed_template(title=title, description=description)
        await ctx.send(embed=embed)
Ejemplo n.º 19
0
    async def draft(self):
        """ Start the team draft and return the teams after it's finished. """
        # Initialize
        self.members_left = self.members.copy(
        )  # Copy members to edit players remaining in the player pool
        self.players = await self.bot.api_helper.get_players(
            [member.id for member in self.members])
        self.teams = [[], []]
        self.pick_number = 0
        captain_method = await self.bot.get_pug_data(self.channel.category,
                                                     'captain_method')

        if captain_method == 'rank':
            players = await self.bot.api_helper.get_players(
                [member.id for member in self.members_left])
            players.sort(reverse=True, key=lambda x: x.score)

            for team in self.teams:
                captain = self.guild.get_member(players.pop(0).discord)
                self.members_left.remove(captain)
                team.append(captain)
        elif captain_method == 'random':
            temp_members = self.members_left.copy()
            shuffle(temp_members)

            for team in self.teams:
                captain = temp_members.pop()
                self.members_left.remove(captain)
                team.append(captain)
        elif captain_method == 'volunteer':
            pass
        else:
            raise ValueError(f'Captain method "{captain_method}" isn\'t valid')

        await self.edit(embed=self._picker_embed(translate('team-draft-begun'))
                        )

        items = self.pick_emojis.items()
        for emoji, member in items:
            if member in self.members_left:
                await self.add_reaction(emoji)

        # Add listener handlers and wait until there are no members left to pick
        self.future = self.bot.loop.create_future()
        self.bot.add_listener(self._process_pick, name='on_reaction_add')
        await asyncio.wait_for(self.future, 600)
        self.bot.remove_listener(self._process_pick, name='on_reaction_add')

        return self.teams
Ejemplo n.º 20
0
    async def unlink(self, ctx):
        """ Unlink a player by delete him on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return

        try:
            user = ctx.message.mentions[0]
        except IndexError:
            title = f"{translate('invalid-usage')}: `{self.bot.command_prefix[0]}unlink <mention>`"
        else:
            linked = await self.bot.api_helper.is_linked(user.id)

            if not linked:
                title = translate('already-not-linked')
            else:
                await self.bot.api_helper.unlink_discord(user)
                title = translate('unlinked')
                role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                      'pug_role')
                role = ctx.guild.get_role(role_id)
                await user.remove_roles(role)

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)
Ejemplo n.º 21
0
    def _veto_embed(self, title):
        """ Generate the menu embed based on the current status of the map bans. """
        embed = self.bot.embed_template(title=title)
        embed.set_footer(text=translate('map-veto-footer'))
        maps_str = ''

        if self.map_pool is not None and self.maps_left is not None:
            for m in self.map_pool:
                maps_str += f'{m.emoji}  {m.name}\n' if m.emoji in self.maps_left else f':heavy_multiplication_x:  ' \
                            f'~~{m.name}~~\n '

        status_str = ''

        if self.captains is not None and self._active_picker is not None:
            status_str += f'**{translate("capt1")}:** {self.captains[0].mention}\n'
            status_str += f'**{translate("capt2")}:** {self.captains[1].mention}\n\n'
            status_str += f'**{translate("current-capt")}:** {self._active_picker.mention}'

        embed.add_field(name=f'__{translate("maps-left")}__', value=maps_str)
        embed.add_field(name=f'__{translate("info")}__', value=status_str)
        return embed
Ejemplo n.º 22
0
    def _picker_embed(self, title):
        """ Generate the menu embed based on the current status of the team draft. """
        embed = self.bot.embed_template(title=title)
        embed.set_footer(text=translate('team-pick-footer'))

        for team in self.teams:
            team_name = f'__{translate("team")}__' if len(
                team
            ) == 0 else f'__{translate("team")} {team[0].display_name}__'

            if len(team) == 0:
                team_players = f'_{translate("empty")}_'
            else:
                team_players = '\n'.join(p.display_name for p in team)

            embed.add_field(name=team_name, value=team_players)

        members_left_str = ''

        for index, (emoji, member) in enumerate(self.pick_emojis.items()):
            if not any(member in team for team in self.teams):
                members_left_str += f'{emoji}  [{member.display_name}]({self.players[index].league_profile})  |  {self.players[index].score}\n'
            else:
                members_left_str += f':heavy_multiplication_x:  ~~[{member.display_name}]({self.players[index].league_profile})~~\n'

        embed.insert_field_at(1,
                              name=f'__{translate("players-left")}__',
                              value=members_left_str)

        status_str = ''

        status_str += f'**{translate("capt1")}:** {self.teams[0][0].mention}\n' if len(
            self.teams[0]) else f'**{translate("capt1")}:**\n '
        status_str += f'**{translate("capt2")}:** {self.teams[1][0].mention}\n\n' if len(
            self.teams[1]) else f'**{translate("capt2")}:**\n\n '
        status_str += f'**{translate("current-capt")}:** {self._active_picker.mention}' \
            if self._active_picker is not None else f'**{translate("current-capt")}:**'

        embed.add_field(name=f'__{translate("info")}__', value=status_str)
        return embed
Ejemplo n.º 23
0
    async def _process_pick(self, reaction, member):
        """ Handler function for player pick reactions. """
        # Check that reaction is on this message and member is in the team draft
        if reaction.message.id != self.id or member == self.author:
            return

        # Check that picked player is in the player pool
        pick = self.pick_emojis.get(str(reaction.emoji), None)

        if pick is None or pick not in self.members_left or member not in self.members:
            await self.remove_reaction(reaction, member)
            return

        # Attempt to pick the player for the team
        try:
            self._pick_player(member, pick)
        except PickError as e:  # Player not picked
            await self.remove_reaction(reaction, member)
            title = e.message
        else:  # Player picked
            self.picked_player = reaction.emoji
            title = translate('team-picked', member.display_name,
                              pick.display_name)

        if len(self.members_left) == 1:
            fat_kid_team = self.teams[0] if len(self.teams[0]) <= len(
                self.teams[1]) else self.teams[1]
            fat_kid_team.append(self.members_left.pop(0))
            await self._update_menu(title)
            if self.future is not None:
                self.future.set_result(None)
            return

        if len(self.members_left) == 0:
            await self._update_menu(title)
            if self.future is not None:
                self.future.set_result(None)
            return

        await self._update_menu(title)
Ejemplo n.º 24
0
    async def queue_embed(self, category, title=None):
        """ Method to create the queue embed for a guild. """
        queued_ids = await self.bot.db_helper.get_queued_users(category.id)
        capacity = await self.bot.get_pug_data(category, 'capacity')

        if len(queued_ids) > 1:
            players = await self.bot.api_helper.get_players(queued_ids)
        elif len(queued_ids) == 1:
            players = [await self.bot.api_helper.get_player(queued_ids[0])]

        if title:
            title += f' ({len(queued_ids)}/{capacity})'

        if len(queued_ids) == 0:  # If there are no members in the queue
            queue_str = f'_{translate("queue-is-empty")}_'
        else:  # members still in queue
            queue_str = ''.join(
                f'{num}. [{category.guild.get_member(member_id).display_name}]({players[num - 1].league_profile})\n'
                for num, member_id in enumerate(queued_ids, start=1))

        embed = self.bot.embed_template(title=title, description=queue_str)
        embed.set_footer(text=translate('receive-notification'))
        return embed
Ejemplo n.º 25
0
    async def create(self, ctx, *args):
        args = ' '.join(arg for arg in args)

        if not len(args):
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}create <name>`'
        else:
            category = await ctx.guild.create_category_channel(name=args)
            await self.bot.db_helper.insert_pugs(category.id)
            everyone_role = get(ctx.guild.roles, name='@everyone')
            pug_role = await ctx.guild.create_role(name=f'{args}_linked')
            text_channel_queue = await ctx.guild.create_text_channel(
                name=f'{args}_queue', category=category)
            text_channel_commands = await ctx.guild.create_text_channel(
                name=f'{args}_commands', category=category)
            voice_channel_lobby = await ctx.guild.create_voice_channel(
                name=f'{args} Lobby', category=category, user_limit=10)
            voice_channel_prelobby = await ctx.guild.create_voice_channel(
                name=f'{args} Pre-Lobby', category=category)
            await self.bot.db_helper.update_pug(category.id,
                                                pug_role=pug_role.id)
            await self.bot.db_helper.update_pug(
                category.id, text_queue=text_channel_queue.id)
            await self.bot.db_helper.update_pug(
                category.id, text_commands=text_channel_commands.id)
            await self.bot.db_helper.update_pug(
                category.id, voice_lobby=voice_channel_lobby.id)
            await self.bot.db_helper.update_pug(
                category.id, voice_prelobby=voice_channel_prelobby.id)
            await text_channel_queue.set_permissions(everyone_role,
                                                     send_messages=False)
            await voice_channel_lobby.set_permissions(everyone_role,
                                                      connect=False)
            await voice_channel_lobby.set_permissions(pug_role, connect=True)
            msg = translate('create-league').format(args)

        embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=embed)
Ejemplo n.º 26
0
    def _pick_player(self, picker, pickee):
        """ Process a team captain's player pick, assuming the picker is in the team draft. """
        # Get picking team
        if picker == pickee:
            raise PickError(translate('picker-pick-self', picker.display_name))
        elif not self.teams[0]:
            picking_team = self.teams[0]
            self.members_left.remove(picker)
            picking_team.append(picker)
        elif self.teams[1] == [] and picker == self.teams[0][0]:
            raise PickError(translate('picker-not-turn', picker.display_name))
        elif self.teams[1] == [] and picker in self.teams[0]:
            raise PickError(
                translate('picker-not-captain', picker.display_name))
        elif not self.teams[1]:
            picking_team = self.teams[1]
            self.members_left.remove(picker)
            picking_team.append(picker)
        elif picker == self.teams[0][0]:
            picking_team = self.teams[0]
        elif picker == self.teams[1][0]:
            picking_team = self.teams[1]
        else:
            raise PickError(
                translate('picker-not-captain', picker.display_name))

        # Check if it's picker's turn
        if picker != self._active_picker:
            raise PickError(translate('picker-not-turn', picker.display_name))

        # Prevent picks when team is full
        if len(picking_team) > len(self.members) // 2:
            raise PickError(translate('team-full', picker.display_name))

        self.members_left.remove(pickee)
        picking_team.append(pickee)
        self.pick_number += 1
Ejemplo n.º 27
0
class CommandsCog(commands.Cog):
    """"""
    def __init__(self, bot):
        self.bot = bot
        self.match_cog = self.bot.get_cog('MatchCog')
        self.queue_cog = self.bot.get_cog('QueueCog')

    @commands.command(usage='create <name>',
                      brief=translate('command-create-brief'))
    @commands.has_permissions(administrator=True)
    async def create(self, ctx, *args):
        args = ' '.join(arg for arg in args)

        if not len(args):
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}create <name>`'
        else:
            category = await ctx.guild.create_category_channel(name=args)
            await self.bot.db_helper.insert_pugs(category.id)
            everyone_role = get(ctx.guild.roles, name='@everyone')
            pug_role = await ctx.guild.create_role(name=f'{args}_linked')
            text_channel_queue = await ctx.guild.create_text_channel(
                name=f'{args}_queue', category=category)
            text_channel_commands = await ctx.guild.create_text_channel(
                name=f'{args}_commands', category=category)
            voice_channel_lobby = await ctx.guild.create_voice_channel(
                name=f'{args} Lobby', category=category, user_limit=10)
            voice_channel_prelobby = await ctx.guild.create_voice_channel(
                name=f'{args} Pre-Lobby', category=category)
            await self.bot.db_helper.update_pug(category.id,
                                                pug_role=pug_role.id)
            await self.bot.db_helper.update_pug(
                category.id, text_queue=text_channel_queue.id)
            await self.bot.db_helper.update_pug(
                category.id, text_commands=text_channel_commands.id)
            await self.bot.db_helper.update_pug(
                category.id, voice_lobby=voice_channel_lobby.id)
            await self.bot.db_helper.update_pug(
                category.id, voice_prelobby=voice_channel_prelobby.id)
            await text_channel_queue.set_permissions(everyone_role,
                                                     send_messages=False)
            await voice_channel_lobby.set_permissions(everyone_role,
                                                      connect=False)
            await voice_channel_lobby.set_permissions(pug_role, connect=True)
            msg = translate('create-league').format(args)

        embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=embed)

    @commands.command(brief=translate('command-delete-brief'))
    @commands.has_permissions(administrator=True)
    async def delete(self, ctx):
        if not await self.bot.is_pug_channel(ctx):
            return

        pug_role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                  'pug_role')
        pug_role = ctx.guild.get_role(pug_role_id)
        try:
            await pug_role.delete()
        except NotFound:
            pass

        await self.bot.db_helper.delete_pugs(ctx.channel.category_id)
        for channel in ctx.channel.category.channels + [ctx.channel.category]:
            await channel.delete()

    @commands.command(brief=translate('command-link-brief'))
    async def link(self, ctx):
        """ Link a player by sending them a link to sign in with steam on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return

        is_linked = await self.bot.api_helper.is_linked(ctx.author.id)

        if is_linked:
            player = await self.bot.api_helper.get_player(ctx.author.id)
            title = translate('already-linked', player.steam_profile)
        else:
            link = await self.bot.api_helper.generate_link_url(ctx.author.id)

            if link:
                # Send the author a DM containing this link
                try:
                    await ctx.author.send(translate('dm-link', link))
                    title = translate('link-sent')
                except:
                    title = translate('blocked-dm')
            else:
                title = translate('unknown-error')

        embed = self.bot.embed_template(description=title)
        await ctx.send(content=ctx.author.mention, embed=embed)

    @commands.command(usage='forcelink <mention> <Steam64 ID>',
                      brief=translate('command-forcelink-brief'))
    @commands.has_permissions(administrator=True)
    async def forcelink(self, ctx, *args):
        """ Force link player with steam on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return
        print(int(args[1]), type(int(args[1])))
        try:
            user = ctx.message.mentions[0]
        except IndexError:
            title = f"{translate('invalid-usage')}: `{self.bot.command_prefix[0]}forcelink <mention> <Steam64 ID>`"
        else:
            link = await self.bot.api_helper.force_link_discord(
                user.id, args[1])

            if not link:
                title = 'Sorry! Steam ID is already linked with another discord'
            else:
                title = translate('force-linked', user.display_name, args[1])
                role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                      'pug_role')
                role = ctx.guild.get_role(role_id)
                await user.add_roles(role)
                await self.bot.api_helper.update_discord_name(user)

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(usage='unlink <mention>',
                      brief=translate('command-unlink-brief'))
    @commands.has_permissions(administrator=True)
    async def unlink(self, ctx):
        """ Unlink a player by delete him on the backend. """
        if not await self.bot.is_pug_channel(ctx):
            return

        try:
            user = ctx.message.mentions[0]
        except IndexError:
            title = f"{translate('invalid-usage')}: `{self.bot.command_prefix[0]}unlink <mention>`"
        else:
            linked = await self.bot.api_helper.is_linked(user.id)

            if not linked:
                title = translate('already-not-linked')
            else:
                await self.bot.api_helper.unlink_discord(user)
                title = translate('unlinked')
                role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                      'pug_role')
                role = ctx.guild.get_role(role_id)
                await user.remove_roles(role)

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(brief=translate('command-check-brief'))
    async def check(self, ctx):
        if not await self.bot.is_pug_channel(ctx):
            return

        if not await self.bot.api_helper.is_linked(ctx.author.id):
            msg = translate('discord-not-linked')
        else:
            role_id = await self.bot.get_pug_data(ctx.channel.category,
                                                  'pug_role')
            role = ctx.guild.get_role(role_id)
            await ctx.author.add_roles(role)
            await self.bot.api_helper.update_discord_name(ctx.author)
            msg = translate('discord-get-role')

        embed = self.bot.embed_template(description=msg, color=self.bot.color)
        await ctx.send(content=ctx.author.mention, embed=embed)

    @commands.command(brief=translate('command-empty-brief'))
    @commands.has_permissions(kick_members=True)
    async def empty(self, ctx):
        """ Reset the pug's queue list to empty. """
        if not await self.bot.is_pug_channel(ctx):
            return

        self.queue_cog.block_lobby[ctx.channel.category] = True
        await self.bot.db_helper.delete_all_queued_users(
            ctx.channel.category.id)
        msg = translate('queue-emptied')
        embed = await self.queue_cog.queue_embed(ctx.channel.category, msg)

        lobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                               'voice_lobby')
        prelobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                                  'voice_prelobby')
        lobby = ctx.bot.get_channel(lobby_id)
        prelobby = ctx.bot.get_channel(prelobby_id)

        for player in lobby.members:
            await player.move_to(prelobby)

        self.queue_cog.block_lobby[ctx.channel.category] = False
        _embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=_embed)
        # Update queue display message
        await self.queue_cog.update_last_msg(ctx.channel.category, embed)

    @commands.command(usage='cap [new capacity]',
                      brief=translate('command-cap-brief'))
    @commands.has_permissions(administrator=True)
    async def cap(self, ctx, *args):
        """ Set the queue capacity. """
        if not await self.bot.is_pug_channel(ctx):
            return

        capacity = await self.bot.get_pug_data(ctx.channel.category,
                                               'capacity')

        try:
            new_cap = int(args[0])
        except (IndexError, ValueError):
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}cap <number>`'
        else:
            if new_cap == capacity:
                msg = translate('capacity-already', capacity)
            elif new_cap < 2 or new_cap > 100:
                msg = translate('capacity-out-range')
            else:
                self.queue_cog.block_lobby[ctx.channel.category] = True
                await self.bot.db_helper.delete_all_queued_users(
                    ctx.channel.category_id)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    capacity=new_cap)
                embed = await self.queue_cog.queue_embed(
                    ctx.channel.category, translate('queue-emptied'))
                embed.set_footer(text=translate('queue-emptied-footer'))
                await self.queue_cog.update_last_msg(ctx.channel.category,
                                                     embed)
                msg = translate('set-capacity', new_cap)

                lobby_id = await self.bot.get_pug_data(ctx.channel.category,
                                                       'voice_lobby')
                prelobby_id = await self.bot.get_pug_data(
                    ctx.channel.category, 'voice_prelobby')
                lobby = ctx.bot.get_channel(lobby_id)
                prelobby = ctx.bot.get_channel(prelobby_id)

                for player in lobby.members:
                    await player.move_to(prelobby)

                self.queue_cog.block_lobby[ctx.channel.category] = False
                await lobby.edit(user_limit=new_cap)

        await ctx.send(embed=self.bot.embed_template(title=msg))

    @commands.command(usage='spectators {+|-} <mention> <mention> ...',
                      brief=translate('command-spectators-brief'))
    @commands.has_permissions(administrator=True)
    async def spectators(self, ctx, *args):
        """"""
        if not await self.bot.is_pug_channel(ctx):
            return

        curr_spectator_ids = await self.bot.db_helper.get_spect_users(
            ctx.channel.category_id)
        curr_spectators = [
            ctx.guild.get_member(spectator_id)
            for spectator_id in curr_spectator_ids
        ]
        spectators = ctx.message.mentions

        if not spectators:
            embed = self.bot.embed_template()
            embed.add_field(
                name=f'__Spectators__',
                value='No spectators' if not curr_spectators else ''.join(
                    f'{num}. {member.mention}\n'
                    for num, member in enumerate(curr_spectators, start=1)))
            await ctx.send(embed=embed)
            return

        prefix = args[0]
        title = ''

        if prefix not in ['+', '-']:
            title = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}spectators [+|-] <mention>`'
        else:
            await self.bot.db_helper.delete_queued_users(
                ctx.channel.category_id,
                [spectator.id for spectator in spectators])
            for spectator in spectators:
                if args[0] == '+':
                    if spectator.id not in curr_spectator_ids:
                        await self.bot.db_helper.insert_spect_users(
                            ctx.channel.category_id, spectator.id)
                        title += f'{translate("added-spect", spectator.display_name)}\n'
                    else:
                        title = f'{translate("already-spect", spectator.display_name)}\n'
                elif args[0] == '-':
                    if spectator.id in curr_spectator_ids:
                        await self.bot.db_helper.delete_spect_users(
                            ctx.channel.category_id, spectator.id)
                        title += f'{translate("removed-spect", spectator.display_name)}\n'
                    else:
                        title = f'{translate("already-spect", spectator.display_name)}\n'

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(usage='teams {captains|autobalance|random}',
                      brief=translate('command-teams-brief'))
    @commands.has_permissions(administrator=True)
    async def teams(self, ctx, method=None):
        """ Set or display the method by which teams are created. """
        if not await self.bot.is_pug_channel(ctx):
            return

        team_method = await self.bot.get_pug_data(ctx.channel.category,
                                                  'team_method')
        valid_methods = ['captains', 'autobalance', 'random']

        if method is None:
            title = translate('team-method', team_method)
        else:
            method = method.lower()

            if method == team_method:
                title = translate('team-method-already', team_method)
            elif method in valid_methods:
                title = translate('set-team-method', method)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    team_method=method)
            else:
                title = translate('team-valid-methods', valid_methods[0],
                                  valid_methods[1], valid_methods[2])

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(usage='captains {volunteer|rank|random}',
                      brief=translate('command-captains-brief'))
    @commands.has_permissions(administrator=True)
    async def captains(self, ctx, method=None):
        """ Set or display the method by which captains are selected. """
        if not await self.bot.is_pug_channel(ctx):
            return

        guild_data = await self.bot.db_helper.get_pug(ctx.channel.category_id)
        captain_method = guild_data['captain_method']
        valid_methods = ['volunteer', 'rank', 'random']

        if method is None:
            title = translate('captains-method', captain_method)
        else:
            method = method.lower()

            if method == captain_method:
                title = translate('captains-method-already', captain_method)
            elif method in valid_methods:
                title = translate('set-captains-method', method)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    captain_method=method)
            else:
                title = translate('captains-valid-method', valid_methods[0],
                                  valid_methods[1], valid_methods[2])

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(usage='mpool {+|-}<map name> ...',
                      brief=translate('command-mpool-brief'))
    @commands.has_permissions(administrator=True)
    async def mpool(self, ctx, *args):
        """ Edit the guild's map pool for map drafts. """
        if not await self.bot.is_pug_channel(ctx):
            return

        map_pool = [
            m.dev_name for m in self.bot.all_maps.values()
            if await self.bot.get_pug_data(ctx.channel.category, m.dev_name)
        ]

        if len(args) == 0:
            embed = self.bot.embed_template(title=translate('map-pool'))
        else:
            description = ''
            any_wrong_arg = False  # Indicates if the command was used correctly

            for arg in args:
                map_name = arg[1:]  # Remove +/- prefix
                map_obj = next((m for m in self.bot.all_maps.values()
                                if m.dev_name == map_name), None)

                if map_obj is None:
                    description += '\u2022 ' + translate(
                        'could-not-interpret', arg)
                    any_wrong_arg = True
                    continue

                if arg.startswith('+'):  # Add map
                    if map_name not in map_pool:
                        map_pool.append(map_name)
                        description += '\u2022 ' + translate(
                            'added-map', map_name)
                elif arg.startswith('-'):  # Remove map
                    if map_name in map_pool:
                        map_pool.remove(map_name)
                        description += '\u2022 ' + translate(
                            'removed-map', map_name)

            if len(map_pool) < 3:
                description = translate('map-pool-fewer-3')
            else:
                map_pool_data = {
                    m.dev_name: m.dev_name in map_pool
                    for m in self.bot.all_maps.values()
                }
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    **map_pool_data)

            embed = self.bot.embed_template(
                title=translate('modified-map-pool'), description=description)

            if any_wrong_arg:  # Add example usage footer if command was used incorrectly
                embed.set_footer(
                    text=
                    f'Ex: {self.bot.command_prefix[0]}mpool +de_cache -de_mirage'
                )

        active_maps = ''.join(f'{m.emoji}  `{m.dev_name}`\n'
                              for m in self.bot.all_maps.values()
                              if m.dev_name in map_pool)
        inactive_maps = ''.join(f'{m.emoji}  `{m.dev_name}`\n'
                                for m in self.bot.all_maps.values()
                                if m.dev_name not in map_pool)

        if not inactive_maps:
            inactive_maps = f'*{translate("none")}*'

        embed.add_field(name=f'__{translate("active-maps")}__',
                        value=active_maps)
        embed.add_field(name=f'__{translate("inactive-maps")}__',
                        value=inactive_maps)
        await ctx.send(embed=embed)

    @commands.command(usage='maps [{captains|vote|random}]',
                      brief=translate('command-maps-brief'))
    @commands.has_permissions(administrator=True)
    async def maps(self, ctx, method=None):
        """ Set or display the method by which the teams are created. """
        if not await self.bot.is_pug_channel(ctx):
            return

        map_method = await self.bot.get_pug_data(ctx.channel.category,
                                                 'map_method')
        valid_methods = ['captains', 'vote', 'random']

        if method is None:
            title = translate('map-method', map_method)
        else:
            method = method.lower()

            if method == map_method:
                title = translate('map-method-already', map_method)
            elif method in valid_methods:
                title = translate('set-map-method', method)
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    map_method=method)
            else:
                title = translate('map-valid-method', valid_methods[0],
                                  valid_methods[1], valid_methods[2])

        embed = self.bot.embed_template(title=title)
        await ctx.send(embed=embed)

    @commands.command(usage='end [match id]',
                      brief=translate('command-end-brief'))
    @commands.has_permissions(administrator=True)
    async def end(self, ctx, *args):
        """ Force end a match. """
        if not await self.bot.is_pug_channel(ctx):
            return

        if len(args) == 0:
            msg = f'{translate("invalid-usage")}: `{self.bot.command_prefix[0]}end <Match ID>`'
        else:
            matches = await self.bot.api_helper.matches_status()
            if args[0] in matches:
                if await self.bot.api_helper.end_match(args[0]):
                    msg = translate("match-cancelled", args[0])
                else:
                    msg = translate('match-already-over', args[0])
            else:
                msg = translate("invalid-match-id")

        embed = self.bot.embed_template(title=msg)
        await ctx.send(embed=embed)

    @commands.command(brief=translate('command-stats-brief'))
    async def stats(self, ctx):
        """ Send an embed containing stats data parsed from the player object returned from the API. """
        if not await self.bot.is_pug_channel(ctx):
            return

        try:
            user = ctx.message.mentions[0]
        except IndexError:
            user = ctx.author

        player = await self.bot.api_helper.get_player(user.id)

        if player:
            win_percent_str = f'{player.win_percent * 100:.2f}%'
            hs_percent_str = f'{player.hs_percent * 100:.2f}%'
            fb_percent_str = f'{player.first_blood_rate * 100:.2f}%'
            description = '```ml\n' \
                          f' {translate("rank-score")}:      {player.score:>6} \n' \
                          f' {translate("matches-played")}:    {player.matches_played:>6} \n' \
                          f' {translate("win-percentage")}:    {win_percent_str:>6} \n' \
                          f' {translate("kd-ratio")}:          {player.kd_ratio:>6.2f} \n' \
                          f' {translate("adr")}:               {player.adr:>6.2f} \n' \
                          f' {translate("hs-percentage")}:     {hs_percent_str:>6} \n' \
                          f' {translate("first-blood-rate")}:  {fb_percent_str:>6} ' \
                          '```'
            embed = self.bot.embed_template(description=description)
            embed.set_author(name=user.display_name,
                             url=player.league_profile,
                             icon_url=user.avatar_url_as(size=128))
        else:
            title = translate("cannot-get-stats", ctx.author.display_name)
            embed = self.bot.embed_template(title=title)

        await ctx.send(embed=embed)

    @commands.command(brief=translate('command-leaders-brief'))
    async def leaders(self, ctx):
        """ Send an embed containing the leaderboard data parsed from the player objects returned from the API. """
        if not await self.bot.is_pug_channel(ctx):
            return

        num = 5  # Easily modfiy the number of players on the leaderboard
        guild_players = await self.bot.api_helper.get_players(
            [user.id for user in ctx.guild.members])

        if len(guild_players) == 0:
            embed = self.bot.embed_template(title=translate("nobody-ranked"))
            await ctx.send(embed=embed)

        guild_players.sort(key=lambda u: (u.score, u.matches_played),
                           reverse=True)

        # Select the top players only
        if len(guild_players) > num:
            guild_players = guild_players[:num]

        # Generate leaderboard text
        data = [
            ['Player'] + [
                ctx.guild.get_member(player.discord).display_name
                for player in guild_players
            ], ['Score'] + [str(player.score) for player in guild_players],
            ['Winrate'] +
            [f'{player.win_percent * 100:.2f}%' for player in guild_players],
            ['Played'] +
            [str(player.matches_played) for player in guild_players]
        ]
        data[0] = [
            name if len(name) < 12 else name[:9] + '...' for name in data[0]
        ]  # Shorten long names
        widths = list(map(lambda x: len(max(x, key=len)), data))
        aligns = ['left', 'right', 'right', 'right']
        z = zip(data, widths, aligns)
        formatted_data = [
            list(map(lambda x: align_text(x, width, align), col))
            for col, width, align in z
        ]
        formatted_data = list(map(
            list, zip(*formatted_data)))  # Transpose list for .format() string
        description = '```ml\n    {}  {}  {}  {} \n'.format(*formatted_data[0])

        for rank, player_row in enumerate(formatted_data[1:], start=1):
            description += ' {}. {}  {}  {}  {} \n'.format(rank, *player_row)

        description += '```'

        # Send leaderboard
        title = f'__{translate("server-leaderboard")}__'
        embed = self.bot.embed_template(title=title, description=description)
        await ctx.send(embed=embed)

    @create.error
    @delete.error
    @empty.error
    @cap.error
    @spectators.error
    @teams.error
    @captains.error
    @maps.error
    @mpool.error
    @end.error
    @unlink.error
    @forcelink.error
    async def config_error(self, ctx, error):
        """ Respond to a permissions error with an explanation message. """
        if isinstance(error, commands.MissingPermissions):
            await ctx.trigger_typing()
            missing_perm = error.missing_perms[0].replace('_', ' ')
            embed = self.bot.embed_template(
                title=translate('required-perm', missing_perm))
            await ctx.send(embed=embed)
Ejemplo n.º 28
0
 async def help(self, ctx):
     """ Generate and send help embed based on the bot's commands. """
     embed = self.help_embed(translate('league-commands'))
     await ctx.send(embed=embed)
Ejemplo n.º 29
0
    async def on_voice_state_update(self, member, before, after):
        if before.channel == after.channel:
            return

        try:
            after_id = await self.bot.get_pug_data(after.channel.category,
                                                   'voice_lobby')
        except AttributeError:
            after_id = None

        try:
            before_id = await self.bot.get_pug_data(before.channel.category,
                                                    'voice_lobby')
        except AttributeError:
            before_id = None

        before_lobby = member.guild.get_channel(before_id)
        after_lobby = member.guild.get_channel(after_id)

        if after.channel == after_lobby is not None:
            if self.block_lobby[after_lobby.category]:
                return

            if not await self.bot.api_helper.is_linked(
                    member.id):  # Message author isn't linked
                title = translate('account-not-linked', member.display_name)
            else:  # Message author is linked
                awaitables = [
                    self.bot.api_helper.get_player(member.id),
                    self.bot.db_helper.insert_users(member.id),
                    self.bot.db_helper.get_queued_users(
                        after_lobby.category_id),
                    self.bot.get_pug_data(after_lobby.category, 'capacity'),
                    self.bot.db_helper.get_spect_users(after_lobby.category_id)
                ]
                results = await asyncio.gather(*awaitables, loop=self.bot.loop)
                player = results[0]
                queue_ids = results[2]
                capacity = results[3]
                spect_ids = results[4]

                if member.id in queue_ids:  # Author already in queue
                    title = translate('already-in-queue', member.display_name)
                elif member.id in spect_ids:  # Player in the spectators
                    title = translate('in-spectators', member.display_name)
                elif len(queue_ids) >= capacity:  # Queue full
                    title = translate('queue-is-full', member.display_name)
                elif not player:  # ApiHelper couldn't get player
                    title = translate('cannot-verify-match',
                                      member.display_name)
                elif player.in_match:  # member is already in a match
                    title = translate('already-in-match', member.display_name)
                else:  # member can be added
                    await self.bot.db_helper.insert_queued_users(
                        after_lobby.category_id, member.id)
                    queue_ids += [member.id]
                    title = translate('added-to-queue', member.display_name)

                    # Check and burst queue if full
                    if len(queue_ids) == capacity:
                        self.block_lobby[after_lobby.category] = True
                        match_cog = self.bot.get_cog('MatchCog')
                        pug_role_id = await self.bot.get_pug_data(
                            after_lobby.category, 'pug_role')
                        pug_role = member.guild.get_role(pug_role_id)
                        await after_lobby.set_permissions(pug_role,
                                                          connect=False)
                        queue_members = [
                            member.guild.get_member(member_id)
                            for member_id in queue_ids
                        ]
                        all_readied = await match_cog.start_match(
                            after_lobby.category, queue_members)

                        if all_readied:
                            await self.bot.db_helper.delete_queued_users(
                                after_lobby.category_id, *queue_ids)

                        if match_cog.no_servers[after_lobby.category]:
                            await self.bot.db_helper.delete_queued_users(
                                after_lobby.category_id, *queue_ids)
                            prelobby_id = await self.bot.get_pug_data(
                                after_lobby.category, 'voice_prelobby')
                            prelobby = after_lobby.guild.get_channel(
                                prelobby_id)
                            for member in queue_members:
                                try:
                                    await member.move_to(prelobby)
                                except (AttributeError, HTTPException):
                                    pass
                            match_cog.no_servers[after_lobby.category] = False

                        self.block_lobby[after_lobby.category] = False
                        await after_lobby.set_permissions(pug_role,
                                                          connect=True)
                        title = translate('players-in-queue')
                        embed = await self.queue_embed(after_lobby.category,
                                                       title)
                        await self.update_last_msg(after_lobby.category, embed)
                        return

            embed = await self.queue_embed(after_lobby.category, title)
            # Delete last queue message
            await self.update_last_msg(after_lobby.category, embed)

        if before.channel == before_lobby is not None:
            if self.block_lobby[before_lobby.category]:
                return

            removed = await self.bot.db_helper.delete_queued_users(
                before_lobby.category_id, member.id)

            if member.id in removed:
                title = translate('removed-from-queue', member.display_name)
            else:
                title = translate('not-in-queue', member.display_name)

            embed = await self.queue_embed(before_lobby.category, title)
            # Update queue display message
            await self.update_last_msg(before_lobby.category, embed)
Ejemplo n.º 30
0
    async def mpool(self, ctx, *args):
        """ Edit the guild's map pool for map drafts. """
        if not await self.bot.is_pug_channel(ctx):
            return

        map_pool = [
            m.dev_name for m in self.bot.all_maps.values()
            if await self.bot.get_pug_data(ctx.channel.category, m.dev_name)
        ]

        if len(args) == 0:
            embed = self.bot.embed_template(title=translate('map-pool'))
        else:
            description = ''
            any_wrong_arg = False  # Indicates if the command was used correctly

            for arg in args:
                map_name = arg[1:]  # Remove +/- prefix
                map_obj = next((m for m in self.bot.all_maps.values()
                                if m.dev_name == map_name), None)

                if map_obj is None:
                    description += '\u2022 ' + translate(
                        'could-not-interpret', arg)
                    any_wrong_arg = True
                    continue

                if arg.startswith('+'):  # Add map
                    if map_name not in map_pool:
                        map_pool.append(map_name)
                        description += '\u2022 ' + translate(
                            'added-map', map_name)
                elif arg.startswith('-'):  # Remove map
                    if map_name in map_pool:
                        map_pool.remove(map_name)
                        description += '\u2022 ' + translate(
                            'removed-map', map_name)

            if len(map_pool) < 3:
                description = translate('map-pool-fewer-3')
            else:
                map_pool_data = {
                    m.dev_name: m.dev_name in map_pool
                    for m in self.bot.all_maps.values()
                }
                await self.bot.db_helper.update_pug(ctx.channel.category_id,
                                                    **map_pool_data)

            embed = self.bot.embed_template(
                title=translate('modified-map-pool'), description=description)

            if any_wrong_arg:  # Add example usage footer if command was used incorrectly
                embed.set_footer(
                    text=
                    f'Ex: {self.bot.command_prefix[0]}mpool +de_cache -de_mirage'
                )

        active_maps = ''.join(f'{m.emoji}  `{m.dev_name}`\n'
                              for m in self.bot.all_maps.values()
                              if m.dev_name in map_pool)
        inactive_maps = ''.join(f'{m.emoji}  `{m.dev_name}`\n'
                                for m in self.bot.all_maps.values()
                                if m.dev_name not in map_pool)

        if not inactive_maps:
            inactive_maps = f'*{translate("none")}*'

        embed.add_field(name=f'__{translate("active-maps")}__',
                        value=active_maps)
        embed.add_field(name=f'__{translate("inactive-maps")}__',
                        value=inactive_maps)
        await ctx.send(embed=embed)