async def convert(self, ctx, argument): if isinstance(argument, coc.BasicPlayer): return argument tag = coc.utils.correct_tag(argument) name = argument.strip() if tag_validator.match(tag): try: return await ctx.coc.get_player(tag) except coc.NotFound: raise commands.BadArgument( 'I detected a player tag; and couldn\'t ' 'find an account with that tag! ' 'If you didn\'t pass in a tag, ' 'please drop the owner a message.') for rcs_tag in rcs_tags(): clan = await ctx.coc.get_clan(rcs_tag) if clan.name == name or clan.tag == tag: raise commands.BadArgument( f'You appear to be passing ' f'the clan tag/name for `{str(clan)}`') member = clan.get_member(name=name) if member: return member raise commands.BadArgument(f"Invalid tag or IGN. Please try again.")
class TestWarUpdates(commands.Cog, command_attrs=dict(hidden=True)): def __init__(self, bot): self.bot = bot @coc.WarEvents.state(rcs_tags(prefix=True)) async def on_war_state_change(self, current_state, war): channel = self.bot.get_channel(settings['log_channels']['test']) if current_state == "preparation": await channel.send( f"Preparation has just begun for a war between **{war.clan.name}** and " f"**{war.opponent.name}**.") elif current_state == "inWar": await channel.send( f"War has just begun between **{war.clan.name}** and **{war.opponent.name}**." ) elif current_state == "warEnded": content = f"War has just ended between **{war.clan.name}** and **{war.opponent.name}**.\n" if war.status == "won": content += f"{war.clan.name} won!" elif war.status == "lost": content += f"{war.clan.name} lost! :(" else: content += "Looks like a tie!" await channel.send(content) else: await channel.send( f"War state is {current_state} for {war.clan.name}")
async def update_warlog(self): conn = self.bot.pool for tag in helper.rcs_tags(): try: war_log = await self.bot.coc.get_warlog(f"#{tag}") except coc.PrivateWarLog: print(f"{tag} has a private war log.") continue for war in war_log: if war.is_league_entry: # skip all CWL wars continue sql = ( "SELECT war_id, team_size, end_time::timestamp::date, war_state FROM rcs_wars " "WHERE clan_tag = $1 AND opponent_tag = $2 AND end_time < $3" ) fetch = await conn.fetch(sql, tag, war.opponent.tag[1:], datetime.utcnow()) if fetch: # Update existing data in the database for row in fetch: if row['end_time'] == war.end_time.time.date( ) and row['war_state'] != "warEnded": # update database to reflect end of war sql = ( "UPDATE rcs_wars SET war_state = 'warEnded', clan_attacks = $1, " "clan_destruction = $2, clan_stars = $3, " "opponent_destruction = $4, opponent_stars = $5 WHERE war_id = $6" ) await conn.execute(sql, war.clan.attacks_used, war.clan.destruction, war.clan.stars, war.opponent.destruction, war.opponent.stars, row['war_id']) else: # War is not in database, add it (happens if bot is down) if war.end_time.time < datetime.utcnow() - timedelta( days=2): reported = True else: reported = False sql = ( "INSERT INTO rcs_wars (clan_name, clan_tag, clan_attacks, clan_destruction, clan_stars," "opponent_tag, opponent_name, opponent_destruction, opponent_stars," "end_time, war_state, team_size, reported)" "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)" ) await conn.execute(sql, war.clan.name, war.clan.tag[1:], war.clan.attacks_used, war.clan.destruction, war.clan.stars, war.opponent.tag[1:], war.opponent.name, war.opponent.destruction, war.opponent.stars, war.end_time.time, "warEnded", war.team_size, reported) self.bot.logger.info( f"Added war for {war.clan.name} vs {war.opponent.name} ending " f"{war.end_time.time}.")
def __init__(self, bot): self.bot = bot self.guild = None self.media_stats = None self.bot.coc.add_events( self.on_clan_war_win_streak_change, self.on_clan_level_change, self.on_clan_war_win_change, ) self.bot.coc.add_clan_update(rcs_tags(prefix=True)) self.bot.coc.start_updates("clan") self.clan_checks.start() self.rcs_list.start() bot.loop.create_task(self.cog_init_ready())
async def plot_trophy_attack(self, ctx): """Correlation plot for all RCS clans. Determines connections between trophy count and attack wins.""" await ctx.send("Sit tight! This one takes about 70 seconds.", delete_after=60.0) trophies = [] attack_wins = [] async with ctx.typing(): for tag in rcs_tags(prefix=True): clan = await self.bot.coc.get_clan(tag) async for member in clan.get_detailed_members(): if member.trophies > 500 and member.attack_wins > 0: trophies.append(member.trophies) attack_wins.append(member.attack_wins) df = pd.DataFrame({ "Trophy Count": trophies, "Attack Wins": attack_wins }) df.plot(kind="scatter", y="Attack Wins", x="Trophy Count") plt.savefig(fname='plot') await ctx.send(file=discord.File('plot.png'))
async def cwl(self, ctx, *args): """List CWL leagues of all RCS clans **Example:** ++cwl - Shows list of RCS clans in their leagues """ sort_leagues = cwl_league_order[::-1] cwl_clans = {} for league in sort_leagues: cwl_clans[league] = [] for tag in rcs_tags(): clan = await self.bot.coc.get_clan(tag) league = clan.war_league.name.replace("League ", "") cwl_clans[league].append(f"{clan.name} ({clan.tag})") for league in sort_leagues: content = header_only = f"**{league}:**\n" for clan in cwl_clans[league]: content += f" {clan}\n" if content != header_only: await ctx.send(content)
async def games_start(self, ctx): """For starting games manually""" conn = self.bot.pool games = await self.get_current_games() games_id = games['games_id'] to_insert = [] async for clan in self.bot.coc.get_clans(rcs_tags(prefix=True)): counter = 1 async for member in clan.get_detailed_members(): to_insert.append( (counter, games_id, member.tag[1:], clan.tag[1:], member.get_achievement("Games Champion").value, member.get_achievement("Games Champion").value)) counter += 1 sql = ( "INSERT INTO rcs_clan_games (event_id, player_tag, clan_tag, starting_points, current_points) " "SELECT x.event_id, x.player_tag, x.clan_tag, x.starting_points, x.current_points " "FROM unnest($1::rcs_clan_games[]) as x") await conn.execute(sql, to_insert) await ctx.send(f"Added {counter} games records for the current games.")
async def start_games(self): """Task to pull initial Games data for the new clan games""" now = datetime.utcnow() conn = self.bot.pool games_id, start_time = await self.get_next_games() if games_id: print(f"start_games:\n Start Time: {start_time}") if start_time - now < timedelta(minutes=10): to_insert = [] async for clan in self.bot.coc.get_clans( rcs_tags(prefix=True)): counter = 1 async for member in clan.get_detailed_members(): to_insert.append( (counter, games_id, member.tag[1:], clan.tag[1:], member.get_achievement("Games Champion").value, member.get_achievement("Games Champion").value)) counter += 1 sql = ( "INSERT INTO rcs_clan_games (event_id, player_tag, clan_tag, starting_points, current_points) " "SELECT x.event_id, x.player_tag, x.clan_tag, x.starting_points, x.current_points " "FROM unnest($1::rcs_clan_games[]) as x") await conn.execute(sql, to_insert)
async def on_ready(self): activity = discord.Game("Clash of Clans") await self.change_presence(status=discord.Status.online, activity=activity) self.coc.add_clan_updates(*rcs_tags(prefix=True))
async def leader_notes(self): """Check the leader-notes channel and see if any of those players are in an RCS clan""" if datetime.utcnow().hour != 16: return danger_channel = self.bot.get_channel( settings['rcs_channels']['danger_bot']) notes_channel = self.bot.get_channel( settings['rcs_channels']['leader_notes']) messages = "" async for message in notes_channel.history(limit=None, oldest_first=True): if message.content: messages += message.content + " - " regex = r"[tT]ag:\s[PYLQGRJCUV0289]+|#[PYLQGRJCUV0289]{6,}" ban_list = [] for match in re.finditer(regex, messages): if not match.group().startswith("#"): new_match = match.group().upper().replace("TAG: ", "#") else: new_match = match.group().upper() if new_match not in ban_list: ban_list.append(new_match) self.bot.logger.debug(f"ban_list has {len(ban_list)} items") for tag in ban_list: if len(tag) < 6: self.bot.logger.debug(f"Short tag: {tag}") try: player = await self.bot.coc.get_player(tag) if player.clan and player.clan.tag[1:] in rcs_tags(): with Sql() as cursor: sql = ("SELECT COUNT(timestamp) AS reported " "FROM rcs_notify " "WHERE memberTag = %s AND clanTag = %s") cursor.execute(sql, (player.tag[1:], player.clan.tag[1:])) row = cursor.fetchone() reported = row[0] if reported < 3: clan = get_clan(player.clan.tag[1:]) await danger_channel.send(f"<@{clan['leaderTag']}>" ) embed = discord.Embed( color=discord.Color.dark_red()) embed.add_field( name="Leader Note found:", value= f"{player.name} ({player.tag}) is in {player.clan.name}. Please " f"search for `in:leader-notes {player.tag}` for details." ) embed.set_footer( text= "Reminder: This is not a ban list, simply information that this " "member has caused problems in the past.") await danger_channel.send(embed=embed) sql = ("INSERT INTO rcs_notify " "VALUES (%s, %s, %s)") cursor.execute( sql, (datetime.now().strftime('%m-%d-%Y %H:%M:%S'), player.clan.tag[1:], player.tag[1:])) except coc.NotFound: self.bot.logger.warning(f"Exception on tag: {tag}") except: self.bot.logger.exception("Other failure") # Add to task log sql = ( "INSERT INTO rcs_task_log (log_type_id, log_date, argument) " "VALUES ($1, $2, $3)") try: await self.bot.pool.execute(sql, log_types['danger'], date.today(), f"{len(ban_list)} tags processed") except: self.bot.logger.exception("RCS Task Log insert error")
async def push_start(self, ctx): msg = await ctx.send("Starting process...") # start push start = time.perf_counter() player_list = [] async for clan in self.bot.coc.get_clans(rcs_tags()): if clan.tag == "#9L2PRL0U": # Change to in list if more than one clan bails continue for member in clan.itermembers: player_list.append(member.tag) team_boom = [ '#20PCPRJ8', '#2QG2C9LG8', '#288UUGPGG', '#YQCVUGJU', '#2G0YV209J', '#9P0PPJV8', '#9PYP8VY90', '#982V9288G', '#2Q8GQLU9R', '#22LPCGV8', '#RU9LYLG9', '#28VYCQGRU', '#P2P9QU8C2', '#GVJP200U', '#20CCV90UQ', '#Y9C2909R', '#2UL9UVCC2', '#89QQ9QRJ0', '#8JQGGU2Q0', '#GPUQYRJC', '#R8JVUGVU', '#V8UQ0G0L', '#G82J00P', '#8VQY0GP2', '#88Y0YL98P', '#80LPL9PRP', '#Y0RPYJPC', '#9L9VCYQQ2', '#9P8PCUY8L', '#YY82YY2Y', '#2LQPJVR0', '#2PYQR02GV', '#URLVC082', '#PJ8V0QUU', '#2LJJY8JGQ', '#CYUVGPPQ', '#PY90C2CY', '#L0GYY8V2', '#8L8PLY2Q2', '#LQY0UUV8V', '#2VVQJ9GG2', '#9Y9GCYRJJ', '#8R2QVYYG', '#2VCG8PPVU', '#2UPPC0GUC', '#8LVCUQGRG', '#2LQVURL9L', '#PCR8QGY9', '#2YCV2JRRJ', '#JLPC2GCU' ] player_list.extend(team_boom) print(len(player_list)) players_many = [] to_insert = [] async for player in self.bot.coc.get_players(player_list): players_many.append( (player.tag[1:], player.clan.tag[1:], player.trophies if player.trophies <= 5000 else 5000, player.trophies if player.trophies <= 5000 else 5000, player.best_trophies, player.town_hall, player.name.replace("'", "''"), player.clan.name)) to_insert.append({ "player_tag": player.tag[1:], "clan_tag": player.clan.tag[1:], "starting_trophies": player.trophies if player.trophies <= 5000 else 5000, "current_trophies": player.trophies if player.trophies <= 5000 else 5000, "best_trophies": player.best_trophies, "starting_th_level": player.town_hall, "player_name": player.name.replace("'", "''"), "clan_name": player.clan.name }) print("Player list assembled.") with Sql() as cursor: sql = (f"INSERT INTO rcspush_2020_1 " f"(playerTag, clanTag, startingTrophies, currentTrophies, " f"bestTrophies, startingThLevel, playerName, clanName) " f"VALUES (%s, %s, %d, %d, %d, %d, %s, %s)") cursor.executemany(sql, players_many) sql = ( "UPDATE rcspush_2020_1 SET clanTag = '9L2PRL0U' " "WHERE playerTag IN ('#20PCPRJ8', '#2QG2C9LG8', '#288UUGPGG', '#YQCVUGJU', '#2G0YV209J', " "'#9P0PPJV8', " "'#9PYP8VY90', '#982V9288G', '#2Q8GQLU9R', '#22LPCGV8', '#RU9LYLG9', '#28VYCQGRU', '#P2P9QU8C2', " "'#GVJP200U', '#20CCV90UQ', '#Y9C2909R', '#2UL9UVCC2', '#89QQ9QRJ0', '#8JQGGU2Q0', '#GPUQYRJC', " "'#R8JVUGVU', '#V8UQ0G0L', '#G82J00P', '#8VQY0GP2', '#88Y0YL98P', '#80LPL9PRP', '#Y0RPYJPC', " "'#9L9VCYQQ2', '#9P8PCUY8L', '#YY82YY2Y', '#2LQPJVR0', '#2PYQR02GV', '#URLVC082', '#PJ8V0QUU', " "'#2LJJY8JGQ', '#CYUVGPPQ', '#PY90C2CY', '#L0GYY8V2', '#8L8PLY2Q2', '#LQY0UUV8V', '#2VVQJ9GG2', " "'#9Y9GCYRJJ', '#8R2QVYYG', '#2VCG8PPVU', '#2UPPC0GUC', '#8LVCUQGRG', '#2LQVURL9L', '#PCR8QGY9', " "'#2YCV2JRRJ', '#JLPC2GCU')") cursor.execute(sql) conn = self.bot.pool sql = ( "INSERT INTO rcspush_2020_1 (player_tag, clan_tag, starting_trophies, current_trophies, best_trophies, " "starting_th_level, player_name, clan_name) " "SELECT x.player_tag, x.clan_tag, x.starting_trophies, x.current_trophies, x.best_trophies, " "x.starting_th_level, x.player_name, x.clan_name " "FROM jsonb_to_recordset($1::jsonb) as x (player_tag TEXT, clan_tag TEXT, starting_trophies INTEGER, " "current_trophies INTEGER, best_trophies INTEGER, starting_th_level INTEGER, player_name TEXT, " "clan_name TEXT)") await conn.execute(sql, to_insert) await msg.delete() await ctx.send(f"{len(player_list)} members added. Elapsed time: " f"{(time.perf_counter() - start) / 60:.2f} minutes")
def __init__(self, bot): self.bot = bot self.bot.coc.add_events(self.on_war_state_change) self.bot.coc.add_war_update(rcs_tags(prefix="#")) self.bot.coc.start_updates("war")