def build_raid_message(self, guild, raid_id, embed_texts): timestamp = int( select_one(self.conn, 'Raids', 'time', raid_id)) # Why can't this return an int by itself? time = datetime.datetime.utcfromtimestamp(timestamp) name = select_one(self.conn, 'Raids', 'name', raid_id) tier = select_one(self.conn, 'Raids', 'tier', raid_id) boss = select_one(self.conn, 'Raids', 'boss', raid_id) roster = select_one(self.conn, 'Raids', 'roster', raid_id) player_ids = select(self.conn, 'Players', 'player_id', raid_id) if player_ids: number_of_players = len(player_ids) else: number_of_players = 0 server_tz = TimeCog.get_server_time(guild) server_time = TimeCog.local_time(time, server_tz) header_time = TimeCog.format_time(server_time) + _(" server time") embed_title = _("{0} {1} at {2}").format(name, tier, header_time) embed_description = _("Bosses: {0}").format(boss) embed = discord.Embed(title=embed_title, colour=discord.Colour(0x3498db), description=embed_description) time_string = self.build_time_string(time, guild) embed.add_field(name=_("Time zones:"), value=time_string) if roster: result = select_rows(self.conn, 'Assignment', 'byname, class_name', raid_id) number_of_slots = len(result) # Add first half embed_name = _("Selected line up:") embed_text = "" for row in result[:number_of_slots // 2]: class_names = row[1].split(',') for class_name in class_names: embed_text = embed_text + self.class_emojis_dict[class_name] embed_text = embed_text + ": " + row[0] + "\n" embed.add_field(name=embed_name, value=embed_text) # Add second half embed_name = "\u200B" embed_text = "" for row in result[number_of_slots // 2:]: class_names = row[1].split(',') for class_name in class_names: embed_text = embed_text + self.class_emojis_dict[class_name] embed_text = embed_text + ": " + row[0] + "\n" embed.add_field(name=embed_name, value=embed_text) # Add a field for each embed text for i in range(len(embed_texts)): if i == 0: embed_name = _("The following {0} players are available:" ).format(number_of_players) else: embed_name = "\u200B" embed.add_field(name=embed_name, value=embed_texts[i]) embed.set_footer(text=_("Raid time in your local time (beta)")) embed.timestamp = time return embed
async def background_task(self): bot = self.bot raids = self.raids expiry_time = datetime.timedelta( seconds=7200) # Delete raids after 2 hours. notify_seconds = 300 # Notify raiders 5 minutes before. notify_time = datetime.timedelta(seconds=notify_seconds) current_time = datetime.datetime.utcnow( ) # Raid time is stored in UTC. # Copy the list to iterate over. for raid_id in raids[:]: timestamp = int(select_one(self.conn, 'Raids', 'time', raid_id)) time = datetime.datetime.utcfromtimestamp(timestamp) if current_time >= time - notify_time * 2: channel_id = select_one(self.conn, 'Raids', 'channel_id', raid_id) channel = bot.get_channel(channel_id) if not channel: self.cleanup_old_raid(raid_id, "Raid channel has been deleted.") continue try: post = await channel.fetch_message(raid_id) except discord.NotFound: self.cleanup_old_raid(raid_id, "Raid post already deleted.") except discord.Forbidden: self.cleanup_old_raid( raid_id, "We are missing required permissions to see raid post." ) else: if current_time > time + expiry_time: await post.delete() self.cleanup_old_raid(raid_id, "Deleted expired raid post.") elif current_time < time - notify_time: roster = select_one(self.conn, 'Raids', 'roster', raid_id) if roster: raid_start_msg = _("Gondor calls for aid! ") players = select_rows(self.conn, 'Assignment', 'player_id', raid_id) for player in players: player_id = player[0] if player_id: raid_start_msg = raid_start_msg + "<@{0}> ".format( player_id) raid_start_msg = raid_start_msg + _( "will you answer the call? We are forming for the raid now." ) await channel.send(raid_start_msg, delete_after=notify_seconds * 2) self.conn.commit()
def build_raid_players(self, raid_id, block_size=6): guild_id = select_one(self.conn, 'Raids', 'guild_id', raid_id) guild = self.bot.get_guild(guild_id) columns = 'raid_id, player_id, byname' for name in self.role_names: columns = columns + ", " + name result = select_rows(self.conn, 'players', columns, raid_id) player_strings = [] if result: number_of_players = len(result) number_of_fields = ((number_of_players - 1) // block_size) + 1 # Create the player strings for row in result: i = 2 player_string = row[i] + " " for name in self.role_names: i = i + 1 if row[i]: player_string = player_string + self.class_emojis_dict[ name] player_string = player_string + "\n" player_strings.append(player_string) # Sort the strings by length player_strings.sort(key=len, reverse=True) else: number_of_players = 0 number_of_fields = 1 # Compute number of fields msg = [""] * number_of_fields # Add the players to the fields, spreading large strings. number_of_players_added = 0 remainder = number_of_players % block_size if remainder: cap_index_last_field = number_of_fields * remainder else: cap_index_last_field = number_of_fields * block_size for player_string in player_strings: if number_of_players_added < cap_index_last_field: index = number_of_players_added % number_of_fields else: index = number_of_players_added % (number_of_fields - 1) number_of_players_added = number_of_players_added + 1 msg[index] = msg[index] + player_string # Do not send an empty embed if there are no players. if msg[0] == "": msg[0] = "\u200B" # Check if the length does not exceed embed limit and split if we can. if len(max(msg, key=len)) >= 1024 and block_size >= 2: msg = self.build_raid_players(raid_id, block_size=block_size // 2) return msg
async def background_task(self): bot = self.bot expiry_time = 7200 # Delete raids after 2 hours. notify_time = 300 # Notify raiders 5 minutes before. current_time = datetime.datetime.utcnow().timestamp( ) # Raid time is stored in UTC. cutoff = current_time + 2 * notify_time raids = select_upcoming_raids(self.conn, cutoff) for raid in raids: raid_id = int(raid[0]) channel_id = int(raid[1]) timestamp = int(raid[2]) roster = int(raid[3]) channel = bot.get_channel(channel_id) if not channel: self.cleanup_old_raid(raid_id, "Raid channel has been deleted.") continue try: post = await channel.fetch_message(raid_id) except discord.NotFound: self.cleanup_old_raid(raid_id, "Raid post already deleted.") except discord.Forbidden: self.cleanup_old_raid( raid_id, "We are missing required permissions to see raid post.") else: if current_time > timestamp + expiry_time: await post.delete() self.cleanup_old_raid(raid_id, "Deleted expired raid post.") elif current_time < timestamp - notify_time: raid_start_msg = _( "Gondor calls for aid! Will you answer the call") if roster: players = select_rows(self.conn, 'Assignment', 'player_id', raid_id) for player in players: player_id = player[0] if player_id: raid_start_msg = raid_start_msg + " <@{0}>".format( player_id) raid_start_msg = raid_start_msg + _( "? We are forming for the raid now.") await channel.send(raid_start_msg, delete_after=notify_time * 2) self.conn.commit()
async def get_players(self, author, channel, raid_id): bot = self.bot def check(reaction, user): return user == author timeout = 60 reaction_limit = 20 reactions = alphabet_emojis() reactions = reactions[:reaction_limit] players = select_rows(self.conn, 'Assignment', 'player_id', raid_id) assigned_ids = [ player[0] for player in players if player[0] is not None ] available = select_players(self.conn, 'player_id, byname', raid_id) default_name = _("<Available>") if not available: await channel.send( _("There are no players to assign for this raid!"), delete_after=10) return if len(available) > reaction_limit: available = available[: reaction_limit] # This only works for the first 20 players. await channel.send( _("**Warning**: removing some noobs from available players!"), delete_after=10) msg_content = _( "Please select the player you want to assign a spot in the raid from the list below using the " "corresponding reaction. Assignment will finish after {0}s of no interaction." ).format(timeout) info_msg = await channel.send(msg_content) msg_content = _("Available players:\n*Please wait... Loading*") player_msg = await channel.send(msg_content) for reaction in reactions[:len(available)]: await player_msg.add_reaction(reaction) class_msg_content = _("Select the class for this player.") class_msg = await channel.send(class_msg_content) for reaction in self.class_emojis: await class_msg.add_reaction(reaction) while True: # Update player msg msg_content = _("Available players:\n") counter = 0 for player in available: if player[0] in assigned_ids: msg_content = msg_content + str( reactions[counter]) + " ~~" + player[1] + "~~\n" else: msg_content = msg_content + str( reactions[counter]) + " " + player[1] + "\n" counter = counter + 1 await player_msg.edit(content=msg_content) # Get player try: (reaction, user) = await bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await channel.send(_("Player assignment finished!"), delete_after=10) break else: try: index = reactions.index(reaction.emoji) except ValueError: await class_msg.remove_reaction(reaction, user) await channel.send(_("Please select a player first!"), delete_after=10) continue else: await player_msg.remove_reaction(reaction, user) selected_player = available[index] slot = select_one_player(self.conn, 'Assignment', 'slot_id', selected_player[0], raid_id) if slot is not None: # Player already assigned a slot, remove player and reset slot. class_names = ','.join(self.slots_class_names[slot]) assign_player(self.conn, raid_id, slot, None, default_name, class_names) assigned_ids.remove(selected_player[0]) text = _("Removed {0} from the line up!").format( selected_player[1]) await channel.send(text, delete_after=10) await self.update_raid_post(raid_id, channel) continue # Get class try: (reaction, user) = await bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await channel.send(_("Player assignment finished!"), delete_after=10) break else: if str(reaction.emoji) in self.class_emojis: await class_msg.remove_reaction(reaction, user) signup = select_one_player(self.conn, 'Players', reaction.emoji.name, selected_player[0], raid_id) if not signup: text = _("{0} did not sign up with {1}!").format( selected_player[1], str(reaction.emoji)) await channel.send(text, delete_after=10) continue else: await player_msg.remove_reaction(reaction, user) await channel.send( _("That is not a class, please start over!"), delete_after=10) continue # Check for free slot search = '%' + reaction.emoji.name + '%' slot_id = select_one_slot(self.conn, raid_id, search) if slot_id is None: await channel.send( _("There are no slots available for the selected class."), delete_after=10) else: assign_player(self.conn, raid_id, slot_id, *selected_player, reaction.emoji.name) assigned_ids.append(selected_player[0]) msg_content = _("Assigned {0} to {1}.").format( selected_player[1], str(reaction.emoji)) await channel.send(msg_content, delete_after=10) await self.update_raid_post(raid_id, channel) await info_msg.delete() await player_msg.delete() await class_msg.delete() return