import re import copy from helpers import * from db_calls import * from discord.ext import commands, tasks OFFSEASON_FLAG = False class SBaTransaction: def __init__(self, channel, current, move_type, this_week=False, first_team=None, team_role=None): self.players = {} # Example: { : { "player": { Strat Player Dict }, "to": { Strat Team Dict } } } self.teams = {} # Example: { : { "team": { Strat Team Dict }, "role": } } } self.picks = {} # Example: { : { "pick": { Strat Pick Dict }, "to": { Strat Team Dict } } } self.avoid_freeze = True self.channel = channel self.gms = [] self.current = current self.effective_week = current['week'] + 1 if not this_week else current['week'] self.move_type = move_type if first_team and team_role: self.add_team(first_team, team_role) if (first_team and not team_role) or (team_role and not first_team): logging.error(f'Trade creation failed:\nteam: {first_team}\nteam_role: {team_role}') raise ValueError('Trade creation failed') def add_team(self, new_team, role): if new_team['id'] not in self.teams.keys(): self.teams[new_team['id']] = { 'team': new_team, 'role': role } self.gms.append(new_team['gmid']) if new_team['gmid2']: self.gms.append(new_team['gmid2']) return True async def add_player(self, player, to_team): if player['id'] not in self.players.keys(): self.players[player['id']] = { 'player': player, 'to': to_team } await self.send(f'Got it - throwing {player["name"]} onto a plane.') else: await self.send(f'{player["name"]} is already part of this transaction. They\'re heading to ' f'{self.players[player["id"]]["to"]["sname"]}. Try to keep up.') async def add_pick(self, pick, to_team): if pick['id'] not in self.picks.keys(): self.picks[pick['id']] = { 'pick': pick, 'to': to_team } await self.send(f'Okay, {pick["origowner"]["abbrev"]}\'s {pick["round"]} is on the table.') else: await self.send(f'{pick["origowner"]["abbrev"]}\'s {pick["round"]} is already part of the deal. It\'s ' f'going to {self.picks[pick["id"]]["to"]["abbrev"]}. Please try to keep up.') def included_team(self, team): team_abbrev = team['abbrev'] for team in self.teams.values(): if team_abbrev in [team['team']['abbrev'], f'{team["team"]["abbrev"]}IL', f'{team["team"]["abbrev"]}MiL']: return True return False async def not_available(self, player, this_week=False): transactions = await self.get_player_moves(player, this_week) logging.info(f'Is {player["name"]} not available? - {len(transactions)}') if len(transactions) > 0: return True return False def get_gms(self, bot, team=None): if team is None: return [bot.get_user(x) for x in self.gms] else: these_gms = [bot.get_user(self.teams[team]['team']['gmid'])] if self.teams[team]['team']['gmid2']: these_gms.append(bot.get_user(self.teams[team]['team']['gmid2'])) return these_gms async def send(self, content=None, embed=None): return await self.channel.send(content=content, embed=embed) async def show_moves(self, here=True): embed = get_team_embed(f'Week {self.effective_week} Transaction', team=[*self.teams.values()][0]['team']) teams = [self.teams[x]['team']['sname'] for x in self.teams] embed.description = f'{", ".join(teams)}' # Get player string player_string = '' for x in self.players: player_string += f'**{self.players[x]["player"]["name"]}** ({self.players[x]["player"]["wara"]}) from ' \ f'{self.players[x]["player"]["team"]["abbrev"]} to {self.players[x]["to"]["abbrev"]}\n' if len(player_string) == 0: player_string = 'None...yet' embed.add_field(name='Player Moves', value=player_string, inline=False) # Get draft pick string pick_string = '' for x in self.picks: pick_string += f'**{self.picks[x]["pick"]["origowner"]["abbrev"]} {self.picks[x]["pick"]["round"]}** to ' \ f'{self.picks[x]["to"]["abbrev"]}\n' if len(pick_string) > 0: embed.add_field(name='Pick Trades', value=pick_string, inline=False) if here: await self.send(content=None, embed=embed) else: return embed async def timed_delete(self): await self.channel.send('I will delete this channel in 5 minutes.') await asyncio.sleep(300) await self.channel.delete() async def get_player_moves(self, player, this_week): if this_week: return await get_transactions( self.current['season'], week_start=self.current['week'], player_id=player['id'] ) else: return await get_transactions( self.current['season'], week_start=self.effective_week, player_id=player['id'] ) async def check_major_league_errors(self, team): wara = 0 mil_wara = 0 this_team = self.teams[team]['team'] team_roster = await get_players(self.current['season'], this_team['abbrev']) mil_roster = await get_players(self.current['season'], f'{this_team["abbrev"]}MiL') for player in team_roster: wara += team_roster[player]['wara'] for player in mil_roster: mil_wara += mil_roster[player]['wara'] if self.effective_week > self.current['week']: set_moves = await get_transactions( self.current['season'], team_abbrev=this_team['abbrev'], week_start=self.effective_week, week_end=self.effective_week ) freeze_moves = await get_transactions( self.current['season'], team_abbrev=this_team['abbrev'], week_start=self.effective_week, week_end=self.effective_week, frozen=True ) moves = {**set_moves, **freeze_moves} for x in moves: # If player is joining this team, add to roster and add WARa if moves[x]['newteam'] == this_team: team_roster[moves[x]['player']['name']] = moves[x]['player'] wara += moves[x]['player']['wara'] # If player is joining MiL team, add to roster and add WARa elif moves[x]['newteam']['id'] == this_team['id'] + 2: mil_roster[moves[x]['player']['name']] = moves[x]['player'] mil_wara += moves[x]['player']['wara'] # If player is leaving this team, remove from roster and subtract WARa if moves[x]['oldteam'] == this_team: # del team_roster[moves[x]['player']['name']] team_roster.pop(moves[x]['player']['name'], None) wara -= moves[x]['player']['wara'] # If player is leaving MiL team, remove from roster and subtract WARa elif moves[x]['oldteam']['id'] == this_team['id'] + 2: # del team_roster[moves[x]['player']['name']] mil_roster.pop(moves[x]['player']['name'], None) mil_wara -= moves[x]['player']['wara'] for x in self.players: # If player is joining this team, add to roster and add WARa if self.players[x]['to'] == this_team: team_roster[self.players[x]['player']['name']] = self.players[x]['player'] wara += self.players[x]['player']['wara'] # If player is joining MiL team, add to roster and add WARa elif self.players[x]['to']['abbrev'] == f'{this_team["abbrev"]}MiL': mil_roster[self.players[x]['player']['name']] = self.players[x]['player'] mil_wara += self.players[x]['player']['wara'] # If player is joining IL team, remove from roster and cut WARa elif self.players[x]['to']['abbrev'] == f'{this_team["abbrev"]}IL': wara -= self.players[x]['player']['wara'] # If player is leaving this team next week, remove from roster and subtract WARa if self.players[x]['player']['team'] == this_team: team_roster.pop(self.players[x]['player']['name'], None) # 06-13: COMMENTED OUT TO RESOLVE MID-WEEK IL REPLACEMENT BEING SENT BACK DOWN # if self.effective_week != self.current['week']: wara -= self.players[x]['player']['wara'] # If player is leaving MiL team next week, remove from roster and subtract WARa if self.players[x]['player']['team']['abbrev'] == f'{this_team["abbrev"]}MiL': mil_roster.pop(self.players[x]['player']['name'], None) if self.effective_week != self.current['week']: mil_wara -= self.players[x]['player']['wara'] return {'roster': team_roster, 'wara': wara, 'mil_roster': mil_roster, 'mil_wara': mil_wara} # async def check_minor_league_errors(self, ml_team_id): # wara = 0 # this_team = await get_one_team(ml_team_id + 2) # team_roster = await get_players(self.current['season'], this_team['abbrev']) # # for player in team_roster: # wara += team_roster[player]['wara'] # # if self.effective_week > self.current['week']: # set_moves = await get_transactions( # self.current['season'], team_abbrev=this_team['abbrev'], week_start=self.effective_week, # week_end=self.effective_week # ) # freeze_moves = await get_transactions( # self.current['season'], team_abbrev=this_team['abbrev'], week_start=self.effective_week, # week_end=self.effective_week, frozen=True # ) # moves = {**set_moves, **freeze_moves} # # for x in moves: # # If player is joining this team, add to roster and add WARa # if moves[x]['newteam'] == this_team: # team_roster[moves[x]['player']['name']] = moves[x]['player'] # wara += moves[x]['player']['wara'] # # If player is leaving this team, remove from roster and subtract WARa # else: # # del team_roster[moves[x]['player']['name']] # team_roster.pop(moves[x]['player']['name'], None) # wara -= moves[x]['player']['wara'] # # for x in self.players: # # If player is joining this team, add to roster and add WARa # if self.players[x]['to'] == this_team: # team_roster[self.players[x]['player']['name']] = self.players[x]['player'] # wara += self.players[x]['player']['wara'] # # If player is leaving this team next week, remove from roster and subtract WARa # elif self.players[x]['player']['team'] == this_team: # team_roster.pop(self.players[x]['player']['name'], None) # if self.effective_week != self.current['week']: # wara -= self.players[x]['player']['wara'] # # return {'roster': team_roster, 'wara': wara} async def send_transaction(self): team_id = list(self.teams.keys())[0] moveid = f'Week-{self.effective_week:0>2}-{datetime.datetime.now().strftime("%d-%H:%M:%S")}' moves = [] logging.warning(f'move_id: {moveid} / move_type: {self.move_type} / avoid_freeze: {self.avoid_freeze} / ' f'week: {self.current["week"]}') if self.current['freeze'] and not self.avoid_freeze: frozen = True else: frozen = False for x in self.players: moves.append({ 'week': self.effective_week, 'player_id': self.players[x]['player']['id'], 'oldteam_id': self.players[x]['player']['team']['id'], 'newteam_id': self.players[x]['to']['id'], 'season': self.current['season'], 'moveid': moveid, 'frozen': frozen }) await post_transactions(moves) for x in self.picks: await patch_draftpick(self.picks[x]['pick']['id'], owner_id=self.picks[x]['to']['id']) return moveid def __str__(self): trans_string = 'Players:\n' for x in self.players: trans_string += f'{self.players[x]}\n' trans_string += '\nTeams:\n' for x in self.teams: trans_string += f'{self.teams[x]}\n' trans_string += f'\nChannel: {self.channel}\n\nGMs:\n' for x in self.gms: trans_string += f'{x}\n' return trans_string class Transactions(commands.Cog): def __init__(self, bot): self.bot = bot self.trade_season = False self.weekly_loop.start() async def cog_command_error(self, ctx, error): await ctx.send(f'{error}') @tasks.loop(minutes=1) async def weekly_loop(self): try: guild = self.bot.get_guild(int(os.environ.get('GUILD_ID'))) if not guild: logging.error(f'Could not pull guild; exiting loop') return except Exception as e: logging.error(f'Could not run weekly_loop: {e}') return current = await get_current() now = datetime.datetime.now() logging.info(f'Datetime: {now} / weekday: {now.weekday()}') # Begin Freeze # if now.weekday() == 0 and now.hour == 5 and not current['freeze']: # Spring/Summer if now.weekday() == 0 and now.hour == 6 and not current['freeze']: # Fall/Winter current['week'] += 1 if OFFSEASON_FLAG: if not self.trade_season: await patch_current(week=current['week']) await self.run_transactions(current) stars = f'{"":*<26}' freeze_message = f'```\n' \ f'{stars}\n' \ f' IT\'S TRADE SZN BITCHES\n' \ f'{stars}\n```' logging.info(f'Freeze string:\n\n{freeze_message}') await send_to_channel(self.bot, 'sba-network-news', freeze_message) self.trade_season = True else: await patch_current(week=current['week'], freeze=True) await self.run_transactions(current) await self.update_roster_sheet(current['season']) logging.info(f'Building freeze string') week_num = f'Week {current["week"]}' stars = f'{"":*<32}' freeze_message = f'```\n' \ f'{stars}\n'\ f'{week_num: >9} Freeze Period Begins\n' \ f'{stars}\n```' logging.info(f'Freeze string:\n\n{freeze_message}') await send_to_channel(self.bot, 'transaction-log', freeze_message) # End Freeze # elif now.weekday() == 5 and now.hour == 5 and current['freeze']: # Spring/Summer elif now.weekday() == 5 and now.hour == 6 and current['freeze']: # Fall/Winter if not OFFSEASON_FLAG: await patch_current(freeze=False) week_num = f'Week {current["week"]}' stars = f'{"":*<30}' freeze_message = f'```\n' \ f'{stars}\n'\ f'{week_num: >9} Freeze Period Ends\n' \ f'{stars}\n```' await self.process_freeze_moves(current) await send_to_channel(self.bot, 'transaction-log', freeze_message) self.trade_season = False async def run_transactions(self, current): all_moves = await get_transactions(current['season'], week_start=current['week'], week_end=current['week']) if len(all_moves) == 0: return for move in [*all_moves.values()]: try: if (move['newteam']['abbrev'][-3:] == 'MiL' and move['oldteam']['abbrev'] == 'FA') or \ move['newteam']['abbrev'][-2:] == 'IL' or move['newteam']['abbrev'].lower() == 'fa': dem_week = current['week'] else: dem_week = current['week'] + 1 await patch_player( move['player']['id'], team_id=move['newteam']['id'], demotion_week=dem_week ) except Exception as e: await send_to_channel(self.bot, 'commissioners-office', f'Error running move:\n{move["moveid"]}') async def process_freeze_moves(self, current): all_moves = await get_transactions( season=current['season'], week_start=current['week'], week_end=current['week'] + 1, frozen=True ) if len(all_moves) == 0: logging.warning(f'No transactions to process for the freeze in week {current["week"]}') else: logging.info(f'freeze / all_moves: {len(all_moves)}') # {'player name': [[Player, TeamAdding, moveid], [Player, OtherTeamAdding, moveid]]} added_players = {} contested_players = {} for move in [*all_moves.values()]: team_record = await get_team_record(move['newteam'], week_num=current["week"]) tiebreaker = team_record["pct"] + (random.randint(10000, 99999) * .00000001) if move["player"]["name"] not in added_players.keys(): added_players[move["player"]["name"]] = [[move["player"], move["newteam"], tiebreaker, move["moveid"]]] else: added_players[move["player"]["name"]].append( [move["player"], move["newteam"], tiebreaker, move["moveid"]] ) logging.info(f'freeze / added_players: {added_players.keys()}') # Check added_players for keys (player names) with more than one move in their list for name in added_players: if len(added_players[name]) > 1: contested_players[name] = added_players[name] logging.info(f'freeze / contested_players: {contested_players.keys()}') # Determine winner for contested players, mark moveid cancelled for loser def tiebreaker(val): logging.info(f'tiebreaker: {val}') return val[2] for guy in contested_players: contested_players[guy].sort(key=tiebreaker) first = True logging.info(f'Contested Player: {contested_players[guy]}\n\n') for x in contested_players[guy]: logging.info(f'First: {first} / x: {x}\n\n') if not first: await patch_transaction(move_id=x[3], cancelled=True, frozen=False) else: first = False # Post transactions that are not cancelled final_moves = await get_transactions( season=current['season'], week_start=current["week"], week_end=current["week"] + 1, frozen=True ) these_ids = [] for x in final_moves: if final_moves[x]["moveid"] not in these_ids: these_ids.append(final_moves[x]["moveid"]) # TODO: not sure I like this method of running moves for move_id in these_ids: await patch_transaction(move_id, frozen=False) await self.post_move_to_transaction_log(move_id) await self.send_move_to_sheets(move_id) # # In case there were SIL moves that go this week, run transactions # await self.run_transactions(current) async def send_move_to_sheets(self, move_id): return current = await get_current() sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') trans_tab = sheets.open_by_key(SBA_ROSTER_KEY).worksheet_by_title('Transactions') all_vals = [] all_moves = await get_transactions( season=current['season'], move_id=move_id ) counter = 0 for move in [*all_moves.values()]: all_vals.append([ move['player']['name'], move['oldteam']['sname'], move['newteam']['sname'], move['week'], current['transcount'] + counter ]) counter += 1 try: trans_tab.update_values( crange=f'A{current["transcount"] + 3}', values=all_vals ) await patch_current(transcount=current['transcount'] + counter) except Exception as e: await send_to_channel(self.bot, 'commissioners-office', f'Failed sending move {move_id} to sheets') async def post_move_to_transaction_log(self, move_id): current = await get_current() all_moves = await get_transactions( season=current['season'], move_id=move_id ) this_team = None week_num = None move_string = '' for move in [*all_moves.values()]: if not this_team: if move['oldteam']['abbrev'] != 'FA' and 'IL' not in move['oldteam']['abbrev']: this_team = await get_one_team(move['oldteam']['id']) elif move['newteam']['abbrev'] != 'FA' and 'IL' not in move['newteam']['abbrev']: this_team = await get_one_team(move['newteam']['id']) if not week_num: week_num = move['week'] move_string += f'**{move["player"]["name"]}** ({move["player"]["wara"]}) from ' \ f'{move["oldteam"]["abbrev"]} to {move["newteam"]["abbrev"]}\n' embed = get_team_embed(f'Week {week_num} Transaction', this_team) embed.description = this_team['sname'] embed.add_field(name='Player Moves', value=move_string) await send_to_channel(self.bot, 'transaction-log', embed=embed) async def send_stats_to_sheets(self, channel='commissioners-office', which='all'): current = await get_current() b_stats = None p_stats = None if which == 'all' or which == 'batting': await send_to_channel(self.bot, channel, 'Collecting batting stats...') b_stats = await get_battingstat(current['season'], timeout=90) if which == 'all' or which == 'pitching': await send_to_channel(self.bot, channel, 'Collecting pitching stats...') p_stats = await get_pitchingstat(current['season'], timeout=90) sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') if b_stats: await send_to_channel(self.bot, channel, f'Preparing batting stats ({len(b_stats)} lines found)...') batting_stats = [] for x in [*b_stats.values()]: batting_stats.append([ x['player']['name'], x['team']['abbrev'], x['pos'], x['pa'], x['ab'], x['run'], x['hit'], x['rbi'], x['double'], x['triple'], x['hr'], x['bb'], x['so'], x['hbp'], x['sac'], x['ibb'], x['gidp'], x['sb'], x['cs'], x['xch'], x['xhit'], x['error'], x['pb'], x['sbc'], x['csc'], x['week'], x['game'], f'{x["week"]}.{x["game"]}' ]) await patch_current(bstatcount=len(batting_stats)) await send_to_channel(self.bot, channel, f'Sending {len(batting_stats)} batting lines...') sheets.open_by_key(SBA_STATS_KEY).worksheet_by_title('Batting Data').update_values( crange='A2', values=batting_stats ) await send_to_channel(self.bot, channel, f'Batting stats have been sent') elif which == 'all' or which == 'batting': await send_to_channel(self.bot, channel, 'No batting stats found') if p_stats: await send_to_channel(self.bot, channel, f'Preparing pitching stats ({len(p_stats)} lines found)...') pitching_stats = [] for x in [*p_stats.values()]: pitching_stats.append([ x['player']['name'], x['team']['abbrev'], x['ip'], x['hit'], x['run'], x['erun'], x['so'], x['bb'], x['hbp'], x['wp'], x['balk'], x['hr'], 1 if x['gs'] else 0, 1 if x['win'] else 0, 1 if x['loss'] else 0, 1 if x['hold'] else 0, 1 if x['sv'] else 0, 1 if x['bsv'] else 0, x['week'], x['game'], f'{x["week"]}.{x["game"]}' ]) await patch_current(pstatcount=len(pitching_stats)) await send_to_channel(self.bot, channel, f'Sending {len(pitching_stats)} pitching lines...') sheets.open_by_key(SBA_STATS_KEY).worksheet_by_title('Pitching Data').update_values( crange='A2', values=pitching_stats ) await send_to_channel(self.bot, channel, f'Pitching stats have been sent') elif which == 'all' or which == 'pitching': await send_to_channel(self.bot, channel, 'No pitching stats found') async def update_roster_sheet(self, season): logging.info(f'calling the db') # csv_data = db_get('players', api_ver=2, params=[('season', 6), ('csv', True)], as_csv=True) # csv = DataFrame(csv_data).to_csv(header=False, index=False) # csv = pandas.read_csv(csv_data) ap = await get_players(season) player_data = [ ['name', 'sWAR', 'image', 'vanity_card', 'team_abbrev', 'inj_rat', 'pos_1', 'pos_2', 'pos_3', 'pos_4', 'pos_5', 'pos_6', 'pos_7', 'pos_8', 'last_game', 'last_game2', 'il_return', 'dem_week', 'strat_code', 'bbref_id'] ] for x in ap: player_data.append([ ap[x]['name'], ap[x]['wara'], ap[x]['image'], ap[x]['vanity_card'], ap[x]['team']['abbrev'], ap[x]['injury_rating'], ap[x]['pos_1'], ap[x]['pos_2'], ap[x]['pos_3'], ap[x]['pos_4'], ap[x]['pos_5'], ap[x]['pos_6'], ap[x]['pos_7'], ap[x]['pos_8'], ap[x]['last_game'], ap[x]['last_game2'], ap[x]['il_return'], ap[x]['demotion_week'], ap[x]['strat_code'], ap[x]['bbref_id'] ]) # logging.info(f'\n\nCSV:\n{player_data}\n') # auth sheets logging.info(f'authorizing sheets') sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json', retries=1) # get sheet logging.info(f'getting sheet') master_sheet = sheets.open_by_key(SBA_ROSTER_KEY) # get worksheet logging.info(f'getting worksheet') roster_sheet = master_sheet.worksheet_by_title('API Import') logging.info(f'updating values') roster_sheet.update_values( crange='A1', values=player_data ) @staticmethod def on_team_il(team, player): player_team_abbrev = player['team']['abbrev'] sil_abbrev = f'{team["abbrev"]}IL' mil_abbrev = f'{team["abbrev"]}MiL' if player_team_abbrev in [sil_abbrev, mil_abbrev]: return True else: return False @commands.command(name='run_transactions') @commands.is_owner() async def run_transactions_helper_command(self, ctx): current = await get_current() await self.run_transactions(current) await self.update_roster_sheet(current['season']) await ctx.send(new_rand_conf_gif()) @commands.command(name='process_freeze') @commands.is_owner() async def process_freeze_helper_command(self, ctx): current = await get_current() await self.process_freeze_moves(current) await self.update_roster_sheet(current['season']) await ctx.send(random_conf_gif()) @commands.command(name='trade', help='Trade players') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def trade_command(self, ctx): current = await get_current() if current['week'] > current['trade_deadline']: await ctx.send(await get_emoji(ctx, 'oof', False)) await ctx.send(f'The trade deadline is **week {current["trade_deadline"]}**. Since it is currently **week ' f'{current["week"]}** I am just going to stop you right there.') return if current['week'] < -2: await ctx.send(await get_emoji(ctx, 'oof', False)) await ctx.send(f'Patience, grasshopper. Trades open soon.') return team = await get_team_by_owner(current['season'], ctx.author.id) team_role = get_team_role(ctx, team) player_cog = self.bot.get_cog('Players') poke_role = get_role(ctx, 'Pokétwo') # Create trade channel overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False), team_role: discord.PermissionOverwrite(read_messages=True), ctx.guild.me: discord.PermissionOverwrite(read_messages=True), poke_role: discord.PermissionOverwrite(read_messages=True, send_messages=False)} try: t_channel = await ctx.guild.create_text_channel( f'{team["abbrev"]}-trade', overwrites=overwrites, category=discord.utils.get(ctx.guild.categories, name=f'Transactions') ) # t_channel = await create_channel( # ctx, # channel_name=f'{team["abbrev"]}-trade', # category_name=f'Transactions', # everyone_read=False, # read_send_roles=team_role # ) except Exception as e: await ctx.send(f'{e}\n\n' f'Discord is having issues creating private channels right now. Please try again later.') return # Create trade and post to channel trade = SBaTransaction(t_channel, current, 'trade', first_team=team, team_role=team_role) await trade.send(f'Let\'s start here, {team_role.mention}.') await ctx.send(f'Take my hand... {trade.channel.mention}') intro = await trade.send( 'First, we will add each team involved in the trade. Then I will have you enter each of the players ' 'involved with the trade and where they are going.\n\nOnce that is done, each of the teams involved ' 'will need to confirm the trade.' ) await intro.pin() # Add teams loop while True: prompt = 'Are you adding a team to this deal? (Yes/No)' this_q = Question(self.bot, trade.channel, prompt, 'yesno', 30) resp = await this_q.ask(trade.get_gms(self.bot)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return elif not resp: break else: this_q.prompt = 'Please enter the team\'s abbreviation.' this_q.qtype = 'text' resp = await this_q.ask(trade.get_gms(self.bot)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: try: next_team = await get_one_team(resp) except ValueError: await trade.send('Who the fuck even is that? Try again.') else: next_team_role = get_team_role(ctx, next_team) overwrites[next_team_role] = discord.PermissionOverwrite(read_messages=True) await trade.channel.edit(overwrites=overwrites) trade.add_team(next_team, next_team_role) await trade.send(f'Welcome to the trade, {next_team_role.mention}!') # Get player trades while True: prompt = f'Are you trading a player between teams?' this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300) resp = await this_q.ask(trade.get_gms(self.bot)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return elif not resp: break else: this_q.prompt = 'Which player is being traded?' this_q.qtype = 'text' resp = await this_q.ask(trade.get_gms(self.bot)) if not resp: pass else: try: player = await get_one_player( await fuzzy_player_search(ctx, trade.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await trade.send(f'{await get_emoji(ctx, "squint")}') await trade.send('Who even is that? Try again.') else: # Check that player is on one of the teams # Check that the player hasn't been dropped (IL is okay) if not trade.included_team(player['team']): await trade.send(f'You know that {player["name"]} is on {player["team"]["abbrev"]}, right? ' f'They\'re not part of this trade so...nah.') elif await trade.not_available(player): await trade.send(f'Ope. {player["name"]} is already one the move next week.') else: this_q.prompt = 'Where are they going? Please enter the destination team\'s abbreviation.' resp = await this_q.ask(trade.get_gms(self.bot)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() else: try: dest_team = await get_one_team(resp) except ValueError: await trade.send(f'{await get_emoji(ctx, "facepalm")} They aren\'t even part of ' f'this trade. Come on.') else: if player['team'] == dest_team: await trade.send(f'{await get_emoji(ctx, "lolwhat")} {player["name"]} ' f'is already on {dest_team["abbrev"]}.') elif not trade.included_team(dest_team): await trade.send(f'{await get_emoji(ctx, "lolwhat")} {dest_team["abbrev"]} ' f'isn\'t even part of this trade.') else: await trade.add_player(player, dest_team) await trade.show_moves() # Get pick trades # while True and current['pick_trade_end'] >= current['week'] >= current['pick_trade_start']: # prompt = f'Are you trading any draft picks?' # this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300) # resp = await this_q.ask(trade.get_gms(self.bot)) # effective_season = current['season'] if OFFSEASON_FLAG else current['season'] + 1 # team_season = current['season'] # # if resp is None: # await trade.send('RIP this move. Maybe next time.') # await trade.timed_delete() # return # elif not resp: # break # else: # # Get first pick # this_q.prompt = 'Enter the pick\'s original owner and round number like this: TIT 17' # this_q.qtype = 'text' # resp = await this_q.ask(trade.get_gms(self.bot)) # # if not resp: # await trade.send('RIP this move. Maybe next time.') # await trade.timed_delete() # return # else: # team_abbrev = resp.split(' ')[0] # round_num = resp.split(' ')[1] # try: # first_pick = await get_one_draftpick_search( # effective_season, # orig_owner_abbrev=team_abbrev, # round_num=round_num, # team_season=team_season # ) # except Exception as e: # await trade.send(f'Uh oh, I couldn\'t find **{team_abbrev} {round_num}**. Check the team and ' # f'round number, please.') # else: # this_q.prompt = 'Now enter the return pick\'s original owner and round number like this: TIT 17' # resp = await this_q.ask(trade.get_gms(self.bot)) # # if not resp: # await trade.send('RIP this move. Maybe next time.') # await trade.timed_delete() # return # else: # team_abbrev = resp.split(' ')[0] # round_num = resp.split(' ')[1] # try: # second_pick = await get_one_draftpick_search( # effective_season, # orig_owner_abbrev=team_abbrev, # round_num=round_num, # team_season=team_season # ) # except Exception as e: # await trade.send( # f'Uh oh, I couldn\'t find **{team_abbrev} {round_num}**. Check the team and ' # f'round number, please.') # else: # team_getting_first_pick = second_pick['owner'] # team_getting_second_pick = first_pick['owner'] # # if not trade.included_team(first_pick['owner']): # await trade.send( # f'Imma let you finish, but **{first_pick["owner"]["abbrev"]}** currently holds ' # f'{first_pick["origowner"]["abbrev"]} {first_pick["round"]} and are not part ' # f'of this deal so let\'s try this again.' # ) # else: # if not trade.included_team(second_pick['owner']): # await trade.send( # f'Imma let you finish, but **{second_pick["owner"]["abbrev"]}** currently ' # f'holds {second_pick["origowner"]["abbrev"]} {second_pick["round"]} and ' # f'are not part of this deal so let\'s try this again.' # ) # else: # await trade.add_pick(first_pick, team_getting_first_pick) # await trade.add_pick(second_pick, team_getting_second_pick) # # await trade.show_moves() # FA drops per team if current['week'] > 0: for team in trade.teams: while True: this_q.prompt = f'{trade.teams[team]["role"].mention}\nAre you making an FA drop?' this_q.qtype = 'yesno' resp = await this_q.ask(trade.get_gms(self.bot, team)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you dropping?' this_q.qtype = 'text' resp = await this_q.ask(trade.get_gms(self.bot, team)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, trade.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await trade.send(f'{await get_emoji(ctx, "squint")}') await trade.send('Who even is that? Try again.') else: if not trade.included_team(player['team']): await t_channel.send(f'It looks like {player.name} is on {player.team.abbrev} ' f'so I can\'t let you do that.') # elif player['demotion_week'] > current['week']: # await trade.send(f'Oof. {player["name"]} cannot be dropped until week ' # f'{player["demotion_week"]}.') else: dest_team = await get_one_team('FA') await trade.add_player(player, dest_team) await trade.show_moves() # Check for empty move if len(trade.players) + len(trade.picks) == 0: await trade.send(f'This has been fun. Come again and maybe do something next time.') await trade.timed_delete() return # Check legality for all teams errors = [] for team in trade.teams: data = await trade.check_major_league_errors(team) logging.warning(f'Done checking data - checking WARa now ({data["wara"]}') if data['wara'] > 38.001: errors.append(f'- {trade.teams[team]["team"]["abbrev"]} would have {data["wara"]:.2f} WARa') logging.warning(f'Now checking roster {len(data["roster"])}') if len(data['roster']) > 26: errors.append(f'- {trade.teams[team]["team"]["abbrev"]} would have {len(data["roster"])} players') logging.warning(f'Any errors? {errors}') if data['wara'] > 38.001 or len(data['roster']) > 26: roster_string = '' for x in data['roster']: roster_string += f'{data["roster"][x]["wara"]: >5} - {data["roster"][x]["name"]}\n' errors.append(f'- This is the roster I have for {trade.teams[team]["team"]["abbrev"]}:\n' f'```\n{roster_string}```') if len(errors) > 0: error_message = '\n'.join(errors) await trade.send(f'Yikes. I\'m gonna put the kibosh on this trade. Below is why:\n\n{error_message}') await trade.timed_delete() return # Ask for each team's explict confirmation for team in trade.teams: this_q.prompt = f'{trade.teams[team]["role"].mention}\nDo you accept this trade?' this_q.qtype = 'yesno' resp = await this_q.ask(trade.get_gms(self.bot, team)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: await trade.show_moves() # Run moves trans_id = await trade.send_transaction() await send_to_channel(self.bot, 'transaction-log', embed=await trade.show_moves(here=False)) await trade.send(f'All done! Your transaction id is: {trans_id}') try: choas = get_role(ctx, 'CHOAS ALERT') await send_to_channel(self.bot, f'season-{current["season"]}-chat', f'{choas.mention}') except Exception as e: logging.error(f'Couldn\'t ping chaos for a trade') await trade.timed_delete() @commands.command(name='picktrade', help='Trade draft picks', hidden=True) @commands.is_owner() async def pick_trade_command(self, ctx): current = await get_current() if current['week'] < -2: await ctx.send(await get_emoji(ctx, 'oof', False)) await ctx.send(f'Patience, grasshopper. Trades open up Monday.') return if not OFFSEASON_FLAG: await ctx.send(await get_emoji(ctx, 'oof', False)) await ctx.send(f'You\'ll have to wait, hoss. No pick trades until the offseason.') return team = await get_team_by_owner(current['season'], ctx.author.id) team_role = get_team_role(ctx, team) player_cog = self.bot.get_cog('Players') # Create trade channel overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False), team_role: discord.PermissionOverwrite(read_messages=True), ctx.guild.me: discord.PermissionOverwrite(read_messages=True)} try: # t_channel = await ctx.guild.create_text_channel( # f'{team["abbrev"]}-trade', # overwrites=overwrites, # category=discord.utils.get(ctx.guild.categories, name=f'Transactions') # ) t_channel = await create_channel( ctx, channel_name=f'{team["abbrev"]}-trade', category_name=f'Transactions', everyone_read=False, read_send_roles=team_role ) except Exception as e: await ctx.send(f'{e}\n\n' f'Discord is having issues creating private channels right now. Please try again later.') return # Create trade and post to channel trade = SBaTransaction(t_channel, current, 'trade', first_team=team, team_role=team_role) await trade.send(f'Let\'s start here, {team_role.mention}.') await ctx.send(f'Take my hand... {trade.channel.mention}') intro = await trade.send( 'Alrighty, let\'s collect the pick trades. Once they are all entered, each of the teams involved ' 'will need to confirm the trade.' ) await intro.pin() # Add teams loop while True: prompt = 'Are you adding a team to this deal? (Yes/No)' this_q = Question(self.bot, trade.channel, prompt, 'yesno', 30) resp = await this_q.ask(trade.get_gms(self.bot)) if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return elif not resp: break else: this_q.prompt = 'Please enter the team\'s abbreviation.' this_q.qtype = 'text' resp = await this_q.ask(trade.get_gms(self.bot)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: try: next_team = await get_one_team(resp) except ValueError: await trade.send('Who the fuck even is that? Try again.') else: next_team_role = get_team_role(ctx, next_team) overwrites[next_team_role] = discord.PermissionOverwrite(read_messages=True) await trade.channel.edit(overwrites=overwrites) trade.add_team(next_team, next_team_role) await trade.send(f'Welcome to the trade, {next_team_role.mention}!') # Get pick trades while True: prompt = f'Are you trading any draft picks?' this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300) resp = await this_q.ask(trade.get_gms(self.bot)) effective_season = current['season'] if OFFSEASON_FLAG else current['season'] + 1 team_season = current['season'] if resp is None: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return elif not resp: break else: # Get first pick this_q.prompt = 'Enter the overall pick number being traded.' this_q.qtype = 'int' resp = await this_q.ask(trade.get_gms(self.bot)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: try: first_pick = await get_one_draftpick_byoverall( effective_season, overall=resp ) except Exception as e: await trade.send(f'Frick, I couldn\'t find pick #{resp}.') else: this_q.prompt = 'Now enter the return pick\'s overall pick number.' resp = await this_q.ask(trade.get_gms(self.bot)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: try: second_pick = await get_one_draftpick_byoverall( effective_season, overall=resp ) except Exception as e: await trade.send(f'Frick, I couldn\'t find pick #{resp}.') else: team_getting_first_pick = second_pick['owner'] team_getting_second_pick = first_pick['owner'] if not trade.included_team(first_pick['owner']): await trade.send( f'Ope. **{first_pick["owner"]["abbrev"]}** currently holds ' f'{first_pick["origowner"]["abbrev"]} {first_pick["round"]} and are not part ' f'of this deal so let\'s try this again.' ) else: if not trade.included_team(second_pick['owner']): await trade.send( f'Imma let you finish, but **{second_pick["owner"]["abbrev"]}** currently ' f'holds {second_pick["origowner"]["abbrev"]} {second_pick["round"]} and ' f'are not part of this deal so let\'s try this again.' ) else: await trade.add_pick(first_pick, team_getting_first_pick) await trade.add_pick(second_pick, team_getting_second_pick) await trade.show_moves() # Check for empty move if len(trade.players) + len(trade.picks) == 0: await trade.send(f'This has been fun. Come again and maybe do something next time.') await trade.timed_delete() return # Check legality for all teams errors = [] for team in trade.teams: data = await trade.check_major_league_errors(team) logging.warning(f'Done checking data - checking WARa now ({data["wara"]}') if data['wara'] > 38.001: errors.append(f'- {trade.teams[team]["team"]["abbrev"]} would have {data["wara"]:.2f} WARa') logging.warning(f'Now checking roster {len(data["roster"])}') if len(data['roster']) > 26: errors.append(f'- {trade.teams[team]["team"]["abbrev"]} would have {len(data["roster"])} players') logging.warning(f'Any errors? {errors}') if data['wara'] > 38.001 or len(data['roster']) > 26: roster_string = '' for x in data['roster']: roster_string += f'{data["roster"][x]["wara"]: >5} - {data["roster"][x]["name"]}\n' errors.append(f'- This is the roster I have for {trade.teams[team]["team"]["abbrev"]}:\n' f'```\n{roster_string}```') if len(errors) > 0: error_message = '\n'.join(errors) await trade.send(f'Yikes. I\'m gonna put the kibosh on this trade. Below is why:\n\n{error_message}') await trade.timed_delete() return # Ask for each team's explict confirmation for team in trade.teams: this_q.prompt = f'{trade.teams[team]["role"].mention}\nDo you accept this trade?' this_q.qtype = 'yesno' resp = await this_q.ask(trade.get_gms(self.bot, team)) if not resp: await trade.send('RIP this move. Maybe next time.') await trade.timed_delete() return else: await trade.show_moves() # Run moves trans_id = await trade.send_transaction() await send_to_channel(self.bot, 'sba-network-news', embed=await trade.show_moves(here=False)) await self.send_move_to_sheets(trans_id) await trade.send(f'All done! Your transaction id is: {trans_id}') try: choas = get_role(ctx, 'CHOAS ALERT') await send_to_channel(self.bot, f'season-{current["season"]}-chat', f'{choas.mention}') except Exception as e: logging.error('I was not able to ping CHOAS ALERT') await trade.timed_delete() @commands.command(name='dropadd', aliases=['drop', 'add', 'adddrop', 'longil'], help='FA/MiL moves') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def drop_add_command(self, ctx): current = await get_current() team = await get_team_by_owner(current['season'], ctx.author.id) team_schedule = await get_schedule( current['season'], team_abbrev1=team["abbrev"], week_start=current['week'] + 1, week_end=current['week'] + 1, ) team_role = get_team_role(ctx, team) player_cog = self.bot.get_cog('Players') poke_role = get_role(ctx, 'Pokétwo') if len(team_schedule) == 0 and not OFFSEASON_FLAG and current['week'] != 22: await ctx.send('It looks like your season is over so transactions are locked.') return # Create transaction channel overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False), team_role: discord.PermissionOverwrite(read_messages=True), ctx.guild.me: discord.PermissionOverwrite(read_messages=True), poke_role: discord.PermissionOverwrite(read_messages=True, send_messages=False)} try: t_channel = await ctx.guild.create_text_channel( f'{team["abbrev"]}-transaction', overwrites=overwrites, category=discord.utils.get(ctx.guild.categories, name=f'Transactions') ) except Exception as e: await ctx.send(f'{e}\n\n' f'Discord is having issues creating private channels right now. Please try again later.') return dropadd = SBaTransaction(t_channel, current, 'dropadd', first_team=team, team_role=team_role) await dropadd.send(f'Let\'s start here, {team_role.mention}') await ctx.send(f'Take my hand... {dropadd.channel.mention}') await dropadd.send(f'This transaction is for __next week__. It will go into effect for ' f'week {current["week"] + 1}.') # Get MiL moves while True and not OFFSEASON_FLAG: prompt = f'Are you adding someone to the Minor League roster?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you sending to the MiL?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: fa_team = await get_one_team('FA') dest_team = await get_one_team(f'{team["abbrev"]}MiL') if not dropadd.included_team(player['team']) and player['team'] != fa_team: await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') elif await dropadd.not_available(player): await dropadd.send(f'Uh oh, looks like {player["name"]} is already on the move next week.') elif player['demotion_week'] > current['week']: await dropadd.send(f'Oof. {player["name"]} cannot be dropped until week ' f'{player["demotion_week"]}.') else: if player['team'] == fa_team: dropadd.avoid_freeze = False await dropadd.add_player(player, dest_team) await dropadd.show_moves() # Get Major League Adds while True and not OFFSEASON_FLAG: prompt = f'Are you adding any players to the Major League roster?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you adding?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if OFFSEASON_FLAG: if not self.on_team_il(team, player): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') else: await dropadd.add_player(player, team) else: fa_team = await get_one_team('FA') if player['team'] != fa_team and not self.on_team_il(team, player): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') elif await dropadd.not_available(player): await dropadd.send(f'Uh oh, looks like {player["name"]} is already on the move ' f'next week.') elif player['demotion_week'] > current['week']: await dropadd.send(f'Oof. {player["name"]} cannot be dropped until week ' f'{player["demotion_week"]}.') else: if player['team'] == fa_team: dropadd.avoid_freeze = False await dropadd.add_player(player, team) await dropadd.show_moves() # Get FA Drops while True: prompt = f'Are you dropping anyone to FA?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you dropping to FA?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if not dropadd.included_team(player['team']): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') elif await dropadd.not_available(player): await dropadd.send(f'Uh oh, looks like {player["name"]} is already on the move next week.') elif player['demotion_week'] > current['week']: await dropadd.send(f'Oof. {player["name"]} cannot be dropped until week ' f'{player["demotion_week"]}.') else: dest_team = await get_one_team('FA') await dropadd.add_player(player, dest_team) await dropadd.show_moves() # Check for empty move if len(dropadd.players) == 0: await dropadd.send(f'This has been fun. Come again and maybe do something next time.') await dropadd.timed_delete() return # Check legality errors = [] for team in dropadd.teams: data = await dropadd.check_major_league_errors(team) logging.warning(f'Done checking data - checking WARa now ({data["wara"]})') if data['wara'] > 38.001 and not OFFSEASON_FLAG: errors.append(f'- {dropadd.teams[team]["team"]["abbrev"]} would have {data["wara"]:.2f} sWAR') logging.warning(f'Now checking roster {len(data["roster"])}') if len(data['roster']) > 26: errors.append(f'- {dropadd.teams[team]["team"]["abbrev"]} would have {len(data["roster"])} players') logging.warning(f'Any errors? {errors}') if (data['wara'] > 38.001 and not OFFSEASON_FLAG) or len(data['roster']) > 26: roster_string = '' for x in data['roster']: roster_string += f'{data["roster"][x]["wara"]: >5} - {data["roster"][x]["name"]}\n' errors.append(f'- This is the roster I have for {dropadd.teams[team]["team"]["abbrev"]}:\n' f'```\n{roster_string}```') if len(data['mil_roster']) > 9: errors.append( f'- {dropadd.teams[team]["team"]["abbrev"]}MiL would have {len(data["mil_roster"])} players' ) if len(errors) > 0: error_string = "\n".join(errors) await dropadd.send(f'Woof. Gotta say no to this one. Below is why.\n\n{error_string}') await dropadd.timed_delete() return # Ask for confirmation for team in dropadd.teams: this_q.prompt = f'{dropadd.teams[team]["role"].mention}\nWould you like me to run this move?' this_q.qtype = 'yesno' resp = await this_q.ask(dropadd.get_gms(self.bot, team)) if not resp: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: await dropadd.show_moves() # Run moves trans_id = await dropadd.send_transaction() if not current['freeze'] or dropadd.avoid_freeze: await send_to_channel(self.bot, 'transaction-log', embed=await dropadd.show_moves(here=False)) await dropadd.send(f'All done! Your transaction id is: {trans_id}') await dropadd.timed_delete() @commands.command(name='ilmove', help='IL move') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def il_move_command(self, ctx): current = await get_current() if OFFSEASON_FLAG: await ctx.send(await get_emoji(ctx, 'oof', False)) await ctx.send(f'I\'m not supposed to let anybody make IL moves during the offseason. You can still ' f'trade and drop players to FA, though!') return team = await get_team_by_owner(current['season'], ctx.author.id) team_role = get_team_role(ctx, team) player_cog = self.bot.get_cog('Players') poke_role = get_role(ctx, 'Pokétwo') overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(read_messages=False), team_role: discord.PermissionOverwrite(read_messages=True), ctx.guild.me: discord.PermissionOverwrite(read_messages=True), poke_role: discord.PermissionOverwrite(read_messages=True, send_messages=False)} try: t_channel = await ctx.guild.create_text_channel( f'{team["abbrev"]}-transaction', overwrites=overwrites, category=discord.utils.get(ctx.guild.categories, name=f'Transactions') ) except Exception as e: await ctx.send(f'{e}\n\n' f'Discord is having issues creating private channels right now. Please try again later.') return dropadd = SBaTransaction(t_channel, current, 'dropadd', this_week=True, first_team=team, team_role=team_role) await dropadd.send(f'Let\'s start here, {team_role.mention}') await ctx.send(f'Take my hand... {dropadd.channel.mention}') await dropadd.send(f'This transaction is for __this week__. It will go into effect for week {current["week"]}.') # Get IL moves while True: prompt = f'Are you sending someone to the IL?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you sending to the IL?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if not dropadd.included_team(player['team']): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') else: dest_team = await get_one_team(f'{team["abbrev"]}IL') await dropadd.add_player(player, dest_team) await dropadd.show_moves() # Get Major League Adds while True and not OFFSEASON_FLAG: prompt = f'Are you adding someone to the Major League team?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you adding?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if not self.on_team_il(team, player): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'- you can only call up your MiL players mid-week.') else: await dropadd.add_player(player, team) await dropadd.show_moves() # Get MiL moves while True and not OFFSEASON_FLAG: prompt = f'Are you adding someone to the Minor League team?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you sending to the MiL?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if not dropadd.included_team(player['team']): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') # elif player['demotion_week'] > current['week']: # await dropadd.send(f'Oof. {player["name"]} cannot be dropped until week ' # f'{player["demotion_week"]}.') else: dest_team = await get_one_team(f'{team["abbrev"]}MiL') await dropadd.add_player(player, dest_team) await dropadd.show_moves() # Get FA Drops while True: prompt = f'Are you dropping anyone to FA?' this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300) resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return elif not resp: break else: this_q.prompt = 'Who are you dropping to FA?' this_q.qtype = 'text' resp = await this_q.ask(dropadd.get_gms(self.bot)) if resp is None: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: try: player = await get_one_player( await fuzzy_player_search(ctx, dropadd.channel, self.bot, resp, player_cog.player_list.keys()) ) except ValueError: await dropadd.send(f'{await get_emoji(ctx, "squint")}') await dropadd.send('Who even is that? Try again.') else: if not dropadd.included_team(player['team']): await t_channel.send(f'It looks like {player["name"]} is on {player["team"]["abbrev"]} ' f'so I can\'t let you do that.') # elif player['demotion_week'] > current['week']: # await dropadd.send(f'Oof. {player["name"]} cannot be dropped until week ' # f'{player["demotion_week"]}.') else: dest_team = await get_one_team('FA') await dropadd.add_player(player, dest_team) await dropadd.show_moves() # Check for empty move if len(dropadd.players) == 0: await dropadd.send(f'This has been fun. Come again and maybe do something next time.') await dropadd.timed_delete() return # Check legality errors = [] for team in dropadd.teams: data = await dropadd.check_major_league_errors(team) if data['wara'] > 38.001: errors.append(f'- {dropadd.teams[team]["team"]["abbrev"]} would have {data["wara"]:.2f} WARa') if len(data['roster']) > 26: errors.append(f'- {dropadd.teams[team]["team"]["abbrev"]} would have {len(data["roster"])} players') if data['wara'] > 38.001 or len(data['roster']) > 26: roster_string = '' for x in data['roster']: roster_string += f'{data["roster"][x]["wara"]: >5} - {data["roster"][x]["name"]}\n' errors.append(f'- This is the roster I have for {dropadd.teams[team]["team"]["abbrev"]}:\n' f'```\n{roster_string}```') if len(errors) > 0: error_string = "\n".join(errors) await dropadd.send(f'Woof. Gotta say no to this one. Below is why.\n\n{error_string}') await dropadd.timed_delete() return # Ask for confirmation for team in dropadd.teams: this_q.prompt = f'{dropadd.teams[team]["role"].mention}\nWould you like me to run this move?' this_q.qtype = 'yesno' resp = await this_q.ask(dropadd.get_gms(self.bot, team)) if not resp: await dropadd.send('RIP this move. Maybe next time.') await dropadd.timed_delete() return else: await dropadd.show_moves() # Post moves trans_id = await dropadd.send_transaction() if dropadd.avoid_freeze: # Run moves for player_move in [*dropadd.players.values()]: this_guy = copy.deepcopy(player_move['player']) this_guy['team'] = player_move['to'] await patch_player( player_move['player']['id'], team_id=player_move['to']['id'], demotion_week=current['week'] ) await send_to_channel(self.bot, 'transaction-log', embed=await dropadd.show_moves(here=False)) await self.update_roster_sheet(current['season']) await dropadd.send(f'All done! Your transaction id is: {trans_id}') await dropadd.timed_delete() @commands.command(name='mymoves', help='Show upcoming moves') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def my_moves_command(self, ctx): current = await get_current() team = await get_team_by_owner(current['season'], ctx.author.id) set_moves = await get_transactions( current['season'], team_abbrev=team['abbrev'], week_start=current['week']+1, week_end=current['week']+1 ) frozen_moves = await get_transactions( current['season'], team_abbrev=team['abbrev'], week_start=current['week']+1, week_end=current['week']+1, frozen=True ) logging.info(f'Num Moves: {len(set_moves)}') embed = get_team_embed(f'{team["lname"]} Guaranteed Transactions', team=team) embed.description = f'Week {current["week"] + 1} Moves' guaranteed = {} frozen = {} for x in set_moves: if set_moves[x]["moveid"] not in guaranteed.keys(): guaranteed[set_moves[x]["moveid"]] = [] guaranteed[set_moves[x]["moveid"]].append( f'**{set_moves[x]["player"]["name"]}** ({set_moves[x]["player"]["wara"]}) from ' f'{set_moves[x]["oldteam"]["abbrev"]} to {set_moves[x]["newteam"]["abbrev"]}\n' ) for x in frozen_moves: if frozen_moves[x]["moveid"] not in frozen.keys(): frozen[frozen_moves[x]["moveid"]] = [] frozen[frozen_moves[x]["moveid"]].append( f'**{frozen_moves[x]["player"]["name"]}** ({frozen_moves[x]["player"]["wara"]}) from ' f'{frozen_moves[x]["oldteam"]["abbrev"]} to {frozen_moves[x]["newteam"]["abbrev"]}\n' ) if len(guaranteed) > 0: for move_id in guaranteed: move_string = ''.join(guaranteed[move_id]) embed.add_field(name=f'Trans ID: {move_id}', value=move_string) if len(frozen) > 0: for move_id in frozen: move_string = ''.join(frozen[move_id]) embed.add_field(name=f'Trans ID: {move_id}', value=move_string) await ctx.author.send(content='Hey, boo. Here are your upcoming transactions:', embed=embed) await ctx.author.send('See everything you expected?') @commands.command(name='legal', help='Check roster legality') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def legal_command(self, ctx, *team_abbrev): current = await get_current() if team_abbrev: this_team = await get_one_team(team_abbrev[0]) else: this_team = await get_team_by_owner(current['season'], ctx.author.id) this_week_team = await get_team_roster(this_team, 'current') next_week_team = await get_team_roster(this_team, 'next') count = 0 all_players = [] for roster in [this_week_team, next_week_team]: embed = get_team_embed(f'{this_team["lname"]} Roster Check', team=this_team) if count == 0: embed.description = f'Week {current["week"]}' else: embed.description = f'Week {current["week"] + 1}' errors = [] sil_wara = roster['shortil']['WARa'] total_wara = roster['active']['WARa'] wara_string = f'{total_wara:.2f}' if sil_wara > 0: wara_string += f' ({sil_wara:.2f} IL)' embed.add_field(name='WARa', value=wara_string) if total_wara > 38.001: errors.append(f'- WARa currently {total_wara:.2f} (cap 38.0)') player_count = len(roster["active"]["players"]) embed.add_field(name='Player Count', value=f'{player_count}') if player_count != 26: errors.append(f'- Currently have {player_count} players (need 26)') pos_string = f'```\nC 1B 2B 3B SS\n' \ f'{roster["active"]["C"]} {roster["active"]["1B"]} {roster["active"]["2B"]} ' \ f'{roster["active"]["3B"]} {roster["active"]["SS"]}\n\n' \ f'LF CF RF SP RP\n' \ f'{roster["active"]["LF"]} {roster["active"]["CF"]} {roster["active"]["RF"]} ' \ f'{roster["active"]["SP"]} {roster["active"]["RP"]}\n```' embed.add_field(name='Position Checks', value=pos_string, inline=False) for pos in roster['active']: if pos in ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']: logging.info(f'Pos: {pos} / {roster["active"][pos]}') if roster["active"][pos] < 2: errors.append(f'- Only have {roster["active"][pos]} {pos} (need 2)') # elif pos in ['SP', 'RP']: # logging.info(f'Pos: {pos} / {roster["active"][pos]}') # if roster["active"][pos] < 5: # errors.append(f'- Only have {roster["active"][pos]} {pos} (need 5)') if len(errors) > 0: embed.add_field(name='Legality: ILLEGAL ❌', value="\n".join(errors), inline=False) else: embed.add_field(name='Legality: LEGAL 👍️', value='All good!', inline=False) await ctx.send(content=None, embed=embed) count += 1 @commands.command(name='import', hidden=True) @commands.is_owner() async def import_command(self, ctx, sheet_id, tab_name, test=False): # Get data from Sheets async with ctx.typing(): sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') try: data_sheet = sheets.open_by_key(sheet_id).worksheet_by_title(tab_name) if test: raw_data = data_sheet.get_values('A2', 'C5') else: raw_data = data_sheet.get_values('A2', 'C1100') except Exception as e: logging.error(f'{e}') await ctx.send(f'Yikes. I need a grown-up to read this. I don\'t know what it means:\n\n{e}') return else: await ctx.send(f'Noice - got it! Give me a minute to go through this data...') error_players = [] tba_players = [] fa_team = await get_one_team('FA', 5) async with ctx.typing(): for row in raw_data: if row[0] != '': name = row[0] swar = row[2] try: old_player = await get_one_player(name) except ValueError: error_players.append(name) else: new_player = copy.deepcopy(old_player) new_player['wara'] = swar new_player['season'] = 5 new_player['team_id'] = fa_team['id'] del new_player['il_return'] del new_player['demotion_week'] del new_player['last_game'] del new_player['last_game2'] tba_players.append(new_player) await ctx.send(f'Okay, just read through that sheet. I\'ve got {len(tba_players)} players to add and have ' f'the following errors: {", ".join(error_players)}') logging.info(f'tba_players:\n{tba_players}') if len(tba_players) > 0: async with ctx.typing(): done = await post_players(tba_players) if done: await ctx.send('All done!') @commands.command(name='tomil', help='Post-draft demotions') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def to_mil_command(self, ctx, *player_list): current = await get_current() team = await get_team_by_owner(current['season'], owner_id=ctx.author.id) il_team = await get_one_team(f'{team["abbrev"]}MiL') if current['week'] != 0: logging.info('entering the thot check') await react_and_reply(ctx, '👀', 'https://c.tenor.com/FCAj8xDvEHwAAAAC/be-gone-thot.gif') player_role = get_role(ctx, SBA_PLAYERS_ROLE_NAME) bonked_role = get_role(ctx, 'BAINSHED') logging.info('beginning sleep') await asyncio.sleep(3) # try: # await ctx.author.add_roles(bonked_role) # except Exception as e: # logging.error(f'unable to add {bonked_role} role to {ctx.author}: {e}') try: await ctx.author.remove_roles(player_role) except Exception as e: logging.error(f'unable to remove {player_role} role from {ctx.author}: {e}') return player_list = ' '.join(player_list) player_names = re.split(',', player_list) output_string = '' errors = [] moves = [] for x in player_names: player_cog = self.bot.get_cog('Players') try: player_name = await fuzzy_player_search(ctx, ctx.channel, self.bot, x, player_cog.player_list.keys()) player = await get_one_player(player_name) except Exception as e: logging.error(f'Could not demote {x} for {team["abbrev"]}: {e}') errors.append(x) else: if player['team']['id'] != team['id']: await ctx.send(f'Omg stop trying to make {player["name"]} happen. It\'s not going to happen.') else: output_string += f'**{player["name"]}** ({player["wara"]}) to MiL\n' if player['team']['id'] == team['id']: moves.append({ 'week': 1, 'player_id': player['id'], 'oldteam_id': team['id'], 'newteam_id': il_team['id'], 'season': current['season'], 'moveid': f'draft-tomil-{team["abbrev"]}' }) if len(moves) == 0: await react_and_reply(ctx, '🖕', 'Thanks for that. So much fun.') return await post_transactions(moves) embed = get_team_embed(f'Pre-Season Demotions', team) embed.add_field(name='Demotions', value=output_string, inline=False) await send_to_channel(self.bot, 'transaction-log', content=None, embed=embed) if len(moves) > 0: await react_and_reply(ctx, '✅', random_conf_gif()) if len(errors) > 0: await react_and_reply(ctx, '❌', f'I wasn\'t able to find {", ".join(errors)}') @commands.command(name='calisamazing', help='Make up for your idiocy') async def cal_is_amazing_command(self, ctx): current = await get_current() team = await get_team_by_owner(current['season'], owner_id=ctx.author.id) if not team: await ctx.send(random_conf_gif()) player_role = get_role(ctx, SBA_PLAYERS_ROLE_NAME) try: await ctx.author.add_roles(player_role) except Exception as e: logging.error(f'unable to add {player_role} role to {ctx.author}: {e}') await react_and_reply( ctx, '😩', f'{e}\n\nLooks like you didn\'t apologize hard enough. I can\'t role you back up.') await react_and_reply(ctx, '💖', 'You are too kind.') @commands.command(name='force_roster', help='Mod: Force update roster sheet') async def force_roster_command(self, ctx): current = await get_current() message = await ctx.send('On it...') fake_move = SBaTransaction(ctx.channel, current, 'dropadd') await self.update_roster_sheet(season=current['season']) await message.edit(content=new_rand_conf_gif()) async def setup(bot): await bot.add_cog(Transactions(bot))