diff --git a/cogs/gameplay.py b/cogs/gameplay.py index e20baf7..417febf 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -28,7 +28,7 @@ from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, get_current_play, post_play, get_one_lineup, advance_runners, patch_play, complete_play, get_batting_stats, \ get_pitching_stats, undo_play, get_latest_play, advance_one_runner, count_team_games, get_final_scorebug, \ get_fielding_stats, get_pitching_decisions, get_or_create_bullpen, get_active_games, patch_lineup, \ - get_last_game_ids, get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs + get_last_game_ids, get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs, get_dbready_plays class Gameplay(commands.Cog): @@ -115,7 +115,37 @@ class Gameplay(commands.Cog): await ctx.send(f'{error}\n\nRun !help to see the command requirements') async def slash_error(self, ctx, error): - await ctx.send(f'{error}') + await ctx.send(f'{error[:1600]}') + + async def post_stratgame(self, this_game: StratGame, forfeit: bool = False): + return await db_post('games', payload={ + 'season': this_game.season, + 'game_type': this_game.game_type, + 'away_team_id': this_game.away_team_id, + 'home_team_id': this_game.home_team_id, + 'week': this_game.week_num, + 'ranked': this_game.ranked, + 'short_game': this_game.short_game, + 'forfeit': forfeit + }) + + async def post_allplays(self, this_game: StratGame, final_game_id: int): + all_plays = get_dbready_plays(this_game.id, db_game_id=final_game_id) + await asyncio.sleep(0.5) + return await db_post( + 'plays', + payload={'plays': all_plays}, + timeout=15 + ) + + async def post_decisions(self, this_game: StratGame, final_game_id: int): + all_dec = get_pitching_decisions(this_game, final_game_id) + await asyncio.sleep(0.5) + return await db_post( + 'decisions', + payload={'decisions': all_dec}, + timeout=5 + ) def get_scorebug(self, home_team, away_team, curr_play): occupied = '●' @@ -256,11 +286,6 @@ class Gameplay(commands.Cog): game_state = {'error': False, 'curr_play': curr_play, 'away_team': away_team, 'home_team': home_team} - away_team = await get_game_team(game, team_id=game.away_team_id) - home_team = await get_game_team(game, team_id=game.home_team_id) - game_state['away_team'] = away_team - game_state['home_team'] = home_team - scorebug = self.get_scorebug(home_team, away_team, game_state['curr_play']) game_state['scorebug'] = scorebug @@ -304,6 +329,7 @@ class Gameplay(commands.Cog): game_state['pitcher'] = pitcher game_state['catcher'] = catcher game_state['channel_id'] = game.channel_id + logging.debug(f'game_state: {game_state}') return game_state @@ -326,6 +352,7 @@ class Gameplay(commands.Cog): title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}', color=int(SBA_COLOR, 16) ) + logging.debug(f'got embed') if game.is_pd: footer_text = f'PD Season {PD_SEASON}' @@ -349,15 +376,20 @@ class Gameplay(commands.Cog): return embed + logging.debug(f'no errors') embed.add_field(name='Game State', value=game_state['scorebug'], inline=False) + logging.debug(f'check mercy') if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10: embed.description = '***Mercy rule in effect***' + # embed.color = discord.Colour.red() + logging.debug(f'set pitcher string') pitcher_string = f'{player_link(game, game_state["pitcher"])}' batter_string = f'{game_state["curr_play"].batter.batting_order}. {player_link(game, game_state["batter"])} - ' \ f'{game_state["curr_play"].batter.position}' + logging.debug(f'pull bat stats') all_bat_stats = get_batting_stats(game.id, lineup_id=game_state['curr_play'].batter.id) if len(all_bat_stats): b_s = all_bat_stats[0] @@ -370,6 +402,7 @@ class Gameplay(commands.Cog): if num: batter_string += f', {num if num > 1 else ""}{" " if num > 1 else ""}{stat}' + logging.debug(f'pull pitcher stats') all_pit_stats = get_pitching_stats(game.id, lineup_id=game_state['curr_play'].pitcher.id) if len(all_pit_stats): p_s = all_pit_stats[0] @@ -385,11 +418,13 @@ class Gameplay(commands.Cog): if game.short_game and p_s["pl_outs"] >= 3: pitcher_string += f'\n***F A T I G U E D***' + logging.debug(f'set embed pitcher/batter') # embed.add_field(name='Matchup', value=f'Pitcher: \nvs\nBatter: ', inline=False) embed.add_field(name='Pitcher', value=f'{pitcher_string}') embed.add_field(name='Batter', value=f'{batter_string}') embed.set_image(url=player_bcard(game_state['batter'])) + logging.debug(f'get baserunners') baserunner_string = '' if game_state['curr_play'].on_first: runner = await get_player(game, game_state['curr_play'].on_first) @@ -401,6 +436,7 @@ class Gameplay(commands.Cog): runner = await get_player(game, game_state['curr_play'].on_third) baserunner_string += f'On Third: {player_link(game, runner)}\n' + logging.debug(f'set baserunners') if len(baserunner_string) > 0: embed.add_field(name=' ', value=' ', inline=False) embed.add_field( @@ -414,6 +450,7 @@ class Gameplay(commands.Cog): name='Baserunners', value='None', inline=False ) + logging.debug(f'do AI stuff') # If an AI team is playing if True in [game_state['pitcher']['team']['is_ai'], game_state['batter']['team']['is_ai']]: ai_note = '' @@ -449,6 +486,7 @@ class Gameplay(commands.Cog): inline=False ) + logging.debug(f'if not full length: return embed: {embed}') if not full_length: return embed @@ -1049,7 +1087,7 @@ class Gameplay(commands.Cog): league_name = 'minor-league' else: await interaction.edit_original_response( - content=f'Bonus star for speed running the Minor Leagues. The Major League campaign will release soon!') + content=f'Gold star for speed running the Minor Leagues! The Major League campaign will release soon!') return # elif 'Major' in league: # can_play = False @@ -1599,15 +1637,14 @@ class Gameplay(commands.Cog): return latest_play = get_latest_play(this_game.id) - """ - If the game isn't over - Not 0 outs - Top of inning <= 9 and not 10-run lead - Top 9th inning or earlier and not 10-run lead - """ if latest_play is None: - patch_game(this_game.id, active=False) + await self.post_stratgame(this_game, forfeit=True) + await send_to_channel( + self.bot, 'pd-network-news', + f'The **{owner_team["lname"]}** made an oopsie-poopsie and had to call of their game down in ' + f'{interaction.channel.mention}') + this_game = patch_game(this_game.id, active=False) await interaction.edit_original_response( content='Roger dodger - it is game over.' ) @@ -1625,19 +1662,27 @@ class Gameplay(commands.Cog): elif abs(latest_play.home_score - latest_play.away_score) >= 10 and latest_play.inning_half == 'bot': valid_end = True + valid_end = True # TODO: REMOVE THIS BEFORE GO-LIVE if not valid_end: view = Confirm(responders=[interaction.user]) question = await interaction.channel.send( - 'It doesn\'t look like this game is over, yet. I can end it, but no rewards will be paid out.\n\n' + 'It doesn\'t look like this game is over, yet. I can end it, but no rewards will be paid out and ' + 'you will take the L.\n\n' 'Should I end this game?', view=view ) await view.wait() if view.value: - patch_game(this_game.id, active=False) - await question.edit( - content='Roger dodger - it is game over.', view=None + await question.delete() + await self.post_stratgame(this_game, forfeit=True) + await send_to_channel( + self.bot, 'pd-network-news', + f'The **{owner_team["lname"]}** had to cut out early from their game down in ' + f'{interaction.channel.mention}') + this_game = patch_game(this_game.id, active=False) + await interaction.edit_original_response( + content='Roger dodger - it is game over.' ) return @@ -1658,291 +1703,64 @@ class Gameplay(commands.Cog): await question.edit(content='It stays.', view=None) return - away_team = await db_get('teams', object_id=this_game.away_team_id) - home_team = await db_get('teams', object_id=this_game.home_team_id) + # New database driven stat submission + failure = False + final_game = await self.post_stratgame(this_game) - away_stats = { - # 'p_lines': get_pitching_stats(this_game.id, team_id=away_team['id']), - 'p_lines': [], - 'b_lines': get_batting_stats(this_game.id, team_id=away_team['id']), - 'f_lines': get_fielding_stats(this_game.id, team_id=away_team['id']) - } - home_stats = { - # 'p_lines': get_pitching_stats(this_game.id, team_id=home_team['id']), - 'p_lines': [], - 'b_lines': get_batting_stats(this_game.id, team_id=home_team['id']), - 'f_lines': get_fielding_stats(this_game.id, team_id=home_team['id']), - # 'score': away_stats['p_lines'][0]['tm_runs'] - } - - logging.debug(f'away_stats: {away_stats}\n\nhome_stats: {home_stats}') - - away_pitchers = await get_team_lineups( - this_game.id, team_id=away_team['id'], inc_inactive=True, pitchers_only=True, as_string=False - ) - for line in away_pitchers: - try: - # logging.info(f'line: {line}') - this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) - # logging.info(f'away / this_stats: {this_stats}') - away_stats['p_lines'].extend(this_stats) - if 'score' not in home_stats: - # logging.info(f'score not in home_stats') - home_stats['score'] = this_stats[0]['pl_runs'] - else: - # logging.info(f'score is in home_stats') - home_stats['score'] += this_stats[0]['pl_runs'] - if 'hits' not in home_stats: - # logging.info(f'hits not in home_stats') - home_stats['hits'] = this_stats[0]['pl_hit'] - else: - # logging.info(f'hits is in home_stats') - home_stats['hits'] += this_stats[0]['pl_hit'] - except Exception as e: - bad_player = await get_player(this_game, line) - logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: ' - f'{type(e)}: {e}') - await interaction.edit_original_response( - content=f'I was not able to process stats for {bad_player["name"]} - ' - f'{get_cal_user(interaction).mention} help!') - - home_pitchers = await get_team_lineups( - this_game.id, team_id=home_team['id'], inc_inactive=True, pitchers_only=True, as_string=False - ) - for line in home_pitchers: - try: - # logging.info(f'line: {line}') - this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) - # logging.info(f'home / this_stats: {this_stats}') - home_stats['p_lines'].extend(this_stats) - if 'score' not in away_stats: - # logging.info(f'score not in away_stats') - away_stats['score'] = this_stats[0]['pl_runs'] - else: - # logging.info(f'score is in away_stats') - away_stats['score'] += this_stats[0]['pl_runs'] - if 'hits' not in away_stats: - # logging.info(f'hits not in away_stats') - away_stats['hits'] = this_stats[0]['pl_hit'] - else: - # logging.info(f'hits is in away_stats') - away_stats['hits'] += this_stats[0]['pl_hit'] - except Exception as e: - bad_player = await get_player(this_game, line) - logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: ' - f'{type(e)}: {e}') - await interaction.edit_original_response( - content=f'I was not able to process stats for {bad_player["name"]} - ' - f'{get_cal_user(interaction).mention} help!' - ) - - logging.debug(f'finished tallying pitcher stats') - - # away_stats['score'] = home_stats['p_lines'][0]['tm_runs'] + # Send Plays to db try: - decisions = get_pitching_decisions(this_game) - except AttributeError as e: - logging.error(f'Could not pull decisions for Game {this_game.id}: {e}') - await interaction.edit_original_response( - content=f'I was not able to calculate the Winning and Losing Pitcher for this game. Is the game ' - f'ending early? {get_cal_user(interaction).mention} can probably help.' + resp = await self.post_allplays(this_game, final_game['id']) + if not resp: + failure = True + except Exception as e: + logging.error(f'end-game - Could not post plays: {e}') + failure = True + + # Send Decisions to db + try: + resp = await self.post_decisions(this_game, final_game['id']) + if not resp: + failure = True + except Exception as e: + logging.error(f'end-game - Could not post decisions: {e}') + failure = True + + if failure: + try: + await db_delete(f'decisions/game', object_id=final_game["id"]) + except Exception as e: + logging.error(f'could not delete decisions') + + try: + await db_delete(f'plays/game', object_id=final_game["id"]) + except Exception as e: + logging.error(f'could not delete plays') + + try: + await db_delete(f'games', object_id=final_game["id"]) + except Exception as e: + logging.error(f'could not delete game') + + await interaction.channel.send( + content=f'That did not go well and I wasn\'t able to submit this game. I recommend pinging Cal so he ' + f'can fix this.' ) return - logging.debug(f'decisions: {decisions}') - winning_team = away_team if away_stats['score'] > home_stats['score'] else home_team - losing_team = away_team if away_stats['score'] < home_stats['score'] else home_team + away_team = await db_get('teams', object_id=this_game.away_team_id) + home_team = await db_get('teams', object_id=this_game.home_team_id) + winning_team = away_team if latest_play.away_score > latest_play.home_score else home_team + losing_team = away_team if latest_play.away_score < latest_play.home_score else home_team # Post Game Rewards r_data = await self.post_rewards(winning_team, losing_team, this_game) win_reward = r_data['win_string'] loss_reward = r_data['loss_string'] - # Check for Gauntlet game so rewards go to main team - if gauntlet_team is not None: - if winning_team['gmid'] == gauntlet_team['gmid']: - winning_team = owner_team - else: - losing_team = owner_team - - logging.debug(f'away_stats (in /endgame function)\n\n{away_stats}') - logging.debug(f'home_stats (in /endgame function)\n\n{home_stats}') - logging.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}') - - logging.debug(f'Time to build statlines and submit the scorecard for this PD game!') - # Post result - success = await db_post( - 'results', - payload={ - 'away_team_id': this_game.away_team_id, - 'home_team_id': this_game.home_team_id, - 'away_score': away_stats['score'], - 'home_score': home_stats['score'], - 'away_team_ranking': away_team['ranking'], - 'home_team_ranking': home_team['ranking'], - 'scorecard': f'Bot Game {this_game.id}', - 'week': this_game.week_num, - 'season': this_game.season, - 'ranked': this_game.ranked, - 'short_game': this_game.short_game, - 'game_type': this_game.game_type - } - ) - # Submit the stats - batter_stats = [] - pitcher_stats = [] - doubles = '' - triples = '' - homers = '' - s_bases = '' - caught_s = '' - - for line in [*away_stats['b_lines'], *home_stats['b_lines']]: - if line['pl_double']: - if len(doubles): - doubles += ', ' - card = await db_get("cards", object_id=line["card_id"]) - doubles += f'{card["player"]["p_name"]}' \ - f'{" " if line["pl_double"] > 1 else ""}' \ - f'{line["pl_double"] if line["pl_double"] > 1 else ""}' - if line['pl_triple']: - if len(triples): - triples += ', ' - card = await db_get("cards", object_id=line["card_id"]) - triples += f'{card["player"]["p_name"]}' \ - f'{" " if line["pl_triple"] > 1 else ""}' \ - f'{line["pl_triple"] if line["pl_triple"] > 1 else ""}' - if line['pl_homerun']: - if len(homers): - homers += ', ' - card = await db_get("cards", object_id=line["card_id"]) - homers += f'{card["player"]["p_name"]}' \ - f'{" " if line["pl_homerun"] > 1 else ""}' \ - f'{line["pl_homerun"] if line["pl_homerun"] > 1 else ""}' - if line['pl_sb']: - if len(s_bases): - s_bases += ', ' - card = await db_get("cards", object_id=line["card_id"]) - s_bases += f'{card["player"]["p_name"]}' \ - f'{" " if line["pl_sb"] > 1 else ""}' \ - f'{line["pl_sb"] if line["pl_sb"] > 1 else ""}' - batter_stats.append( - { - 'card_id': line['card_id'], - 'team_id': line['team_id'], - 'roster_num': - this_game.away_roster_num if this_game.away_team_id == line['team_id'] - else this_game.home_roster_num, - 'vs_team_id': - home_team['id'] if this_game.away_team_id == line['team_id'] - else away_team['id'], - 'pos': line['pos'], - 'pa': line['pl_pa'], - 'ab': line['pl_ab'], - 'run': line['pl_run'], - 'rbi': line['pl_rbi'], - 'hit': line['pl_hit'], - 'double': line['pl_double'], - 'triple': line['pl_triple'], - 'hr': line['pl_homerun'], - 'bb': line['pl_bb'], - 'so': line['pl_so'], - 'hbp': line['pl_hbp'], - 'sac': line['pl_sac'], - 'ibb': line['pl_ibb'], - 'gidp': line['pl_gidp'], - 'sb': line['pl_sb'], - 'cs': line['pl_cs'], - 'bphr': line['pl_bphr'], - 'bpfo': line['pl_bpfo'], - 'bp1b': line['pl_bp1b'], - 'bplo': line['pl_bplo'], - 'week': this_game.week_num, - 'season': this_game.season, - 'game_id': this_game.id, - } - ) - - for line in [*away_stats['f_lines'], *home_stats['f_lines']]: - if line['pl_csc']: - if len(caught_s): - caught_s += ', ' - card = await db_get("cards", object_id=line["card_id"]) - caught_s += f'{card["player"]["p_name"]}' \ - f'{" " if line["pl_csc"] > 1 else ""}' \ - f'{line["pl_csc"] if line["pl_csc"] > 1 else ""}' - batter_stats.append( - { - 'card_id': line['card_id'], - 'team_id': line['team_id'], - 'roster_num': - this_game.away_roster_num if this_game.away_team_id == line['team_id'] - else this_game.home_roster_num, - 'vs_team_id': - home_team['id'] if this_game.away_team_id == line['team_id'] - else away_team['id'], - 'pos': line['pos'], - 'xch': line['pl_xch'], - 'xhit': line['pl_xhit'], - 'error': line['pl_error'], - 'pb': line['pl_pb'], - 'sbc': line['pl_sbc'], - 'csc': line['pl_csc'], - 'week': this_game.week_num, - 'season': this_game.season, - 'game_id': this_game.id - } - ) - - for line in [*away_stats['p_lines'], *home_stats['p_lines']]: - pitcher_stats.append( - { - 'card_id': line['card_id'], - 'team_id': line['team_id'], - 'roster_num': - this_game.away_roster_num if this_game.away_team_id == line['team_id'] - else this_game.home_roster_num, - 'vs_team_id': - home_team['id'] if this_game.away_team_id == line['team_id'] - else away_team['id'], - 'ip': (math.floor(line['pl_outs'] / 3) * 1.0) + ((line['pl_outs'] % 3) / 3.0), - 'hit': line['pl_hit'], - 'run': line['pl_runs'], - 'erun': line['pl_eruns'], - 'so': line['pl_so'], - 'bb': line['pl_bb'], - 'hbp': line['pl_hbp'], - 'wp': line['pl_wild_pitch'], - 'balk': line['pl_balk'], - 'hr': line['pl_homerun'], - 'ir': 0, - 'irs': 0, - 'gs': 1 if line['card_id'] in decisions['starters'] else 0, - 'win': 1 if line['card_id'] == decisions['winner'] else 0, - 'loss': 1 if line['card_id'] == decisions['loser'] else 0, - 'hold': 1 if line['card_id'] in decisions['holds'] else 0, - 'sv': 1 if line['card_id'] == decisions['save'] else 0, - 'bsv': 1 if line['card_id'] in decisions['b_save'] else 0, - 'week': this_game.week_num, - 'season': this_game.season, - 'game_id': this_game.id - } - ) - - doubles += '\n' if len(doubles) else '' - triples += '\n' if len(triples) else '' - homers += '\n' if len(homers) else '' - s_bases += '\n' if len(s_bases) else '' - caught_s += '\n' if len(caught_s) else '' - - await db_post('batstats', payload={'stats': batter_stats}) - await db_post('pitstats', payload={'stats': pitcher_stats}) - # Post a notification to PD - last_play = get_current_play(this_game.id) - inning = f'{last_play.inning_num if last_play.inning_half == "Bot" else last_play.inning_num - 1}' + inning = f'{latest_play.inning_num if latest_play.inning_half == "Bot" else latest_play.inning_num - 1}' embed = get_team_embed( - f'{away_team["lname"]} {away_stats["score"]} @ {home_stats["score"]} {home_team["lname"]} - F/' + f'{away_team["lname"]} {latest_play.away_score} @ {latest_play.home_score} {home_team["lname"]} - F/' f'{inning}', winning_team ) @@ -1951,6 +1769,8 @@ class Gameplay(commands.Cog): game_des = 'Major League' elif this_game.game_type == 'minor-league': game_des = 'Minor League' + elif this_game.game_type == 'hall-of-fame': + game_des = 'Hall of Fame' elif this_game.ranked: game_des = 'Ranked' elif 'gauntlet' in this_game.game_type: @@ -1961,40 +1781,13 @@ class Gameplay(commands.Cog): f'{"- 3-Inning Game" if this_game.short_game else " - 9-Inning Game"}' embed.add_field( name='Box Score', - value=get_final_scorebug(away_team, home_team, away_stats, home_stats), + value=f'```\nTeam | R | H | E |\n```', inline=False ) embed.add_field( name='Location', value=f'{interaction.guild.get_channel(this_game.channel_id).mention}' ) - wc_query = await db_get("cards", object_id=decisions["winner"]) - lc_query = await db_get("cards", object_id=decisions["loser"]) - if decisions["save"]: - sv_query = await db_get("cards", object_id=decisions["save"]) - embed.add_field( - name='Pitching', - value=f'Win: {wc_query["player"]["p_name"]}\n' - f'Loss: {lc_query["player"]["p_name"]}\n' - f'{"Save: " if decisions["save"] else ""}' - f'{sv_query["player"]["p_name"] if decisions["save"] else ""}', - inline=False - ) - if len(doubles) + len(triples) + len(homers) > 0: - embed.add_field( - name='Batting', - value=f'{"2B: " if len(doubles) else ""}{doubles if len(doubles) else ""}' - f'{"3B: " if len(triples) else ""}{triples if len(triples) else ""}' - f'{"HR: " if len(homers) else ""}{homers if len(homers) else ""}', - inline=False - ) - if len(s_bases) + len(caught_s) > 0: - embed.add_field( - name='Baserunning', - value=f'{"SB: " if len(s_bases) else ""}{s_bases if len(s_bases) else ""}' - f'{"CSc: " if len(caught_s) else ""}{caught_s if len(caught_s) else ""}', - inline=False - ) embed.add_field( name=f'{winning_team["abbrev"]} Rewards', value=win_reward @@ -2022,23 +1815,410 @@ class Gameplay(commands.Cog): this_run = await db_get('gauntletruns', object_id=int(this_game.game_type.split('-')[3])) if this_run['losses'] == 2: - await send_to_channel( - bot=self.bot, - channel_name='pd-network-news', - content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the ' - f'{this_run["gauntlet"]["name"]} gauntlet.', - embed=None - ) + await send_to_channel( + bot=self.bot, + channel_name='pd-network-news', + content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the ' + f'{this_run["gauntlet"]["name"]} gauntlet.', + embed=None + ) patch_game(this_game.id, active=False) logging.info(f'Game {this_game.id} is complete') if gauntlet_team is None: - await interaction.edit_original_response( - content=f'Good game! Go share the highlights in ' - f'{get_channel(interaction, "pd-news-ticker").mention}!' + await interaction.channel.send( + content=f'Good game! Go share the highlights in ' + f'{get_channel(interaction, "pd-news-ticker").mention}!' ) + """ + END OF THE NEW GAME END + """ + + # away_team = await db_get('teams', object_id=this_game.away_team_id) + # home_team = await db_get('teams', object_id=this_game.home_team_id) + # + # away_stats = { + # # 'p_lines': get_pitching_stats(this_game.id, team_id=away_team['id']), + # 'p_lines': [], + # 'b_lines': get_batting_stats(this_game.id, team_id=away_team['id']), + # 'f_lines': get_fielding_stats(this_game.id, team_id=away_team['id']) + # } + # home_stats = { + # # 'p_lines': get_pitching_stats(this_game.id, team_id=home_team['id']), + # 'p_lines': [], + # 'b_lines': get_batting_stats(this_game.id, team_id=home_team['id']), + # 'f_lines': get_fielding_stats(this_game.id, team_id=home_team['id']), + # # 'score': away_stats['p_lines'][0]['tm_runs'] + # } + # + # logging.debug(f'away_stats: {away_stats}\n\nhome_stats: {home_stats}') + # + # away_pitchers = await get_team_lineups( + # this_game.id, team_id=away_team['id'], inc_inactive=True, pitchers_only=True, as_string=False + # ) + # for line in away_pitchers: + # try: + # # logging.info(f'line: {line}') + # this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) + # # logging.info(f'away / this_stats: {this_stats}') + # away_stats['p_lines'].extend(this_stats) + # if 'score' not in home_stats: + # # logging.info(f'score not in home_stats') + # home_stats['score'] = this_stats[0]['pl_runs'] + # else: + # # logging.info(f'score is in home_stats') + # home_stats['score'] += this_stats[0]['pl_runs'] + # if 'hits' not in home_stats: + # # logging.info(f'hits not in home_stats') + # home_stats['hits'] = this_stats[0]['pl_hit'] + # else: + # # logging.info(f'hits is in home_stats') + # home_stats['hits'] += this_stats[0]['pl_hit'] + # except Exception as e: + # bad_player = await get_player(this_game, line) + # logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: ' + # f'{type(e)}: {e}') + # await interaction.edit_original_response( + # content=f'I was not able to process stats for {bad_player["name"]} - ' + # f'{get_cal_user(interaction).mention} help!') + # + # home_pitchers = await get_team_lineups( + # this_game.id, team_id=home_team['id'], inc_inactive=True, pitchers_only=True, as_string=False + # ) + # for line in home_pitchers: + # try: + # # logging.info(f'line: {line}') + # this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) + # # logging.info(f'home / this_stats: {this_stats}') + # home_stats['p_lines'].extend(this_stats) + # if 'score' not in away_stats: + # # logging.info(f'score not in away_stats') + # away_stats['score'] = this_stats[0]['pl_runs'] + # else: + # # logging.info(f'score is in away_stats') + # away_stats['score'] += this_stats[0]['pl_runs'] + # if 'hits' not in away_stats: + # # logging.info(f'hits not in away_stats') + # away_stats['hits'] = this_stats[0]['pl_hit'] + # else: + # # logging.info(f'hits is in away_stats') + # away_stats['hits'] += this_stats[0]['pl_hit'] + # except Exception as e: + # bad_player = await get_player(this_game, line) + # logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: ' + # f'{type(e)}: {e}') + # await interaction.edit_original_response( + # content=f'I was not able to process stats for {bad_player["name"]} - ' + # f'{get_cal_user(interaction).mention} help!' + # ) + # + # logging.debug(f'finished tallying pitcher stats') + # + # # away_stats['score'] = home_stats['p_lines'][0]['tm_runs'] + # try: + # decisions = get_pitching_decisions(this_game) + # except AttributeError as e: + # logging.error(f'Could not pull decisions for Game {this_game.id}: {e}') + # await interaction.edit_original_response( + # content=f'I was not able to calculate the Winning and Losing Pitcher for this game. Is the game ' + # f'ending early? {get_cal_user(interaction).mention} can probably help.' + # ) + # return + # logging.debug(f'decisions: {decisions}') + # + # winning_team = away_team if away_stats['score'] > home_stats['score'] else home_team + # losing_team = away_team if away_stats['score'] < home_stats['score'] else home_team + # + # # Post Game Rewards + # r_data = await self.post_rewards(winning_team, losing_team, this_game) + # win_reward = r_data['win_string'] + # loss_reward = r_data['loss_string'] + # + # # Check for Gauntlet game so rewards go to main team + # if gauntlet_team is not None: + # if winning_team['gmid'] == gauntlet_team['gmid']: + # winning_team = owner_team + # else: + # losing_team = owner_team + # + # logging.debug(f'away_stats (in /endgame function)\n\n{away_stats}') + # logging.debug(f'home_stats (in /endgame function)\n\n{home_stats}') + # logging.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}') + # + # logging.debug(f'Time to build statlines and submit the scorecard for this PD game!') + # # Post result + # success = await db_post( + # 'results', + # payload={ + # 'away_team_id': this_game.away_team_id, + # 'home_team_id': this_game.home_team_id, + # 'away_score': away_stats['score'], + # 'home_score': home_stats['score'], + # 'away_team_ranking': away_team['ranking'], + # 'home_team_ranking': home_team['ranking'], + # 'scorecard': f'Bot Game {this_game.id}', + # 'week': this_game.week_num, + # 'season': this_game.season, + # 'ranked': this_game.ranked, + # 'short_game': this_game.short_game, + # 'game_type': this_game.game_type + # } + # ) + # # Submit the stats + # batter_stats = [] + # pitcher_stats = [] + # doubles = '' + # triples = '' + # homers = '' + # s_bases = '' + # caught_s = '' + # + # for line in [*away_stats['b_lines'], *home_stats['b_lines']]: + # if line['pl_double']: + # if len(doubles): + # doubles += ', ' + # card = await db_get("cards", object_id=line["card_id"]) + # doubles += f'{card["player"]["p_name"]}' \ + # f'{" " if line["pl_double"] > 1 else ""}' \ + # f'{line["pl_double"] if line["pl_double"] > 1 else ""}' + # if line['pl_triple']: + # if len(triples): + # triples += ', ' + # card = await db_get("cards", object_id=line["card_id"]) + # triples += f'{card["player"]["p_name"]}' \ + # f'{" " if line["pl_triple"] > 1 else ""}' \ + # f'{line["pl_triple"] if line["pl_triple"] > 1 else ""}' + # if line['pl_homerun']: + # if len(homers): + # homers += ', ' + # card = await db_get("cards", object_id=line["card_id"]) + # homers += f'{card["player"]["p_name"]}' \ + # f'{" " if line["pl_homerun"] > 1 else ""}' \ + # f'{line["pl_homerun"] if line["pl_homerun"] > 1 else ""}' + # if line['pl_sb']: + # if len(s_bases): + # s_bases += ', ' + # card = await db_get("cards", object_id=line["card_id"]) + # s_bases += f'{card["player"]["p_name"]}' \ + # f'{" " if line["pl_sb"] > 1 else ""}' \ + # f'{line["pl_sb"] if line["pl_sb"] > 1 else ""}' + # batter_stats.append( + # { + # 'card_id': line['card_id'], + # 'team_id': line['team_id'], + # 'roster_num': + # this_game.away_roster_num if this_game.away_team_id == line['team_id'] + # else this_game.home_roster_num, + # 'vs_team_id': + # home_team['id'] if this_game.away_team_id == line['team_id'] + # else away_team['id'], + # 'pos': line['pos'], + # 'pa': line['pl_pa'], + # 'ab': line['pl_ab'], + # 'run': line['pl_run'], + # 'rbi': line['pl_rbi'], + # 'hit': line['pl_hit'], + # 'double': line['pl_double'], + # 'triple': line['pl_triple'], + # 'hr': line['pl_homerun'], + # 'bb': line['pl_bb'], + # 'so': line['pl_so'], + # 'hbp': line['pl_hbp'], + # 'sac': line['pl_sac'], + # 'ibb': line['pl_ibb'], + # 'gidp': line['pl_gidp'], + # 'sb': line['pl_sb'], + # 'cs': line['pl_cs'], + # 'bphr': line['pl_bphr'], + # 'bpfo': line['pl_bpfo'], + # 'bp1b': line['pl_bp1b'], + # 'bplo': line['pl_bplo'], + # 'week': this_game.week_num, + # 'season': this_game.season, + # 'game_id': this_game.id, + # } + # ) + # + # for line in [*away_stats['f_lines'], *home_stats['f_lines']]: + # if line['pl_csc']: + # if len(caught_s): + # caught_s += ', ' + # card = await db_get("cards", object_id=line["card_id"]) + # caught_s += f'{card["player"]["p_name"]}' \ + # f'{" " if line["pl_csc"] > 1 else ""}' \ + # f'{line["pl_csc"] if line["pl_csc"] > 1 else ""}' + # batter_stats.append( + # { + # 'card_id': line['card_id'], + # 'team_id': line['team_id'], + # 'roster_num': + # this_game.away_roster_num if this_game.away_team_id == line['team_id'] + # else this_game.home_roster_num, + # 'vs_team_id': + # home_team['id'] if this_game.away_team_id == line['team_id'] + # else away_team['id'], + # 'pos': line['pos'], + # 'xch': line['pl_xch'], + # 'xhit': line['pl_xhit'], + # 'error': line['pl_error'], + # 'pb': line['pl_pb'], + # 'sbc': line['pl_sbc'], + # 'csc': line['pl_csc'], + # 'week': this_game.week_num, + # 'season': this_game.season, + # 'game_id': this_game.id + # } + # ) + # + # for line in [*away_stats['p_lines'], *home_stats['p_lines']]: + # pitcher_stats.append( + # { + # 'card_id': line['card_id'], + # 'team_id': line['team_id'], + # 'roster_num': + # this_game.away_roster_num if this_game.away_team_id == line['team_id'] + # else this_game.home_roster_num, + # 'vs_team_id': + # home_team['id'] if this_game.away_team_id == line['team_id'] + # else away_team['id'], + # 'ip': (math.floor(line['pl_outs'] / 3) * 1.0) + ((line['pl_outs'] % 3) / 3.0), + # 'hit': line['pl_hit'], + # 'run': line['pl_runs'], + # 'erun': line['pl_eruns'], + # 'so': line['pl_so'], + # 'bb': line['pl_bb'], + # 'hbp': line['pl_hbp'], + # 'wp': line['pl_wild_pitch'], + # 'balk': line['pl_balk'], + # 'hr': line['pl_homerun'], + # 'ir': 0, + # 'irs': 0, + # 'gs': 1 if line['card_id'] in decisions['starters'] else 0, + # 'win': 1 if line['card_id'] == decisions['winner'] else 0, + # 'loss': 1 if line['card_id'] == decisions['loser'] else 0, + # 'hold': 1 if line['card_id'] in decisions['holds'] else 0, + # 'sv': 1 if line['card_id'] == decisions['save'] else 0, + # 'bsv': 1 if line['card_id'] in decisions['b_save'] else 0, + # 'week': this_game.week_num, + # 'season': this_game.season, + # 'game_id': this_game.id + # } + # ) + # + # doubles += '\n' if len(doubles) else '' + # triples += '\n' if len(triples) else '' + # homers += '\n' if len(homers) else '' + # s_bases += '\n' if len(s_bases) else '' + # caught_s += '\n' if len(caught_s) else '' + # + # await db_post('batstats', payload={'stats': batter_stats}) + # await db_post('pitstats', payload={'stats': pitcher_stats}) + # + # # Post a notification to PD + # last_play = get_current_play(this_game.id) + # inning = f'{last_play.inning_num if last_play.inning_half == "Bot" else last_play.inning_num - 1}' + # embed = get_team_embed( + # f'{away_team["lname"]} {away_stats["score"]} @ {home_stats["score"]} {home_team["lname"]} - F/' + # f'{inning}', + # winning_team + # ) + # + # if this_game.game_type == 'major-league': + # game_des = 'Major League' + # elif this_game.game_type == 'minor-league': + # game_des = 'Minor League' + # elif this_game.game_type == 'hall-of-fame': + # game_des = 'Hall of Fame' + # elif this_game.ranked: + # game_des = 'Ranked' + # elif 'gauntlet' in this_game.game_type: + # game_des = 'Gauntlet' + # else: + # game_des = 'Unlimited' + # embed.description = f'Score Report - {game_des} ' \ + # f'{"- 3-Inning Game" if this_game.short_game else " - 9-Inning Game"}' + # embed.add_field( + # name='Box Score', + # value=get_final_scorebug(away_team, home_team, away_stats, home_stats), + # inline=False + # ) + # embed.add_field( + # name='Location', + # value=f'{interaction.guild.get_channel(this_game.channel_id).mention}' + # ) + # wc_query = await db_get("cards", object_id=decisions["winner"]) + # lc_query = await db_get("cards", object_id=decisions["loser"]) + # if decisions["save"]: + # sv_query = await db_get("cards", object_id=decisions["save"]) + # embed.add_field( + # name='Pitching', + # value=f'Win: {wc_query["player"]["p_name"]}\n' + # f'Loss: {lc_query["player"]["p_name"]}\n' + # f'{"Save: " if decisions["save"] else ""}' + # f'{sv_query["player"]["p_name"] if decisions["save"] else ""}', + # inline=False + # ) + # if len(doubles) + len(triples) + len(homers) > 0: + # embed.add_field( + # name='Batting', + # value=f'{"2B: " if len(doubles) else ""}{doubles if len(doubles) else ""}' + # f'{"3B: " if len(triples) else ""}{triples if len(triples) else ""}' + # f'{"HR: " if len(homers) else ""}{homers if len(homers) else ""}', + # inline=False + # ) + # if len(s_bases) + len(caught_s) > 0: + # embed.add_field( + # name='Baserunning', + # value=f'{"SB: " if len(s_bases) else ""}{s_bases if len(s_bases) else ""}' + # f'{"CSc: " if len(caught_s) else ""}{caught_s if len(caught_s) else ""}', + # inline=False + # ) + # embed.add_field( + # name=f'{winning_team["abbrev"]} Rewards', + # value=win_reward + # ) + # embed.add_field( + # name=f'{losing_team["abbrev"]} Rewards', + # value=loss_reward + # ) + # embed.add_field( + # name='Highlights', + # value=f'Please share the highlights in {get_channel(interaction, "pd-news-ticker").mention}!', + # inline=False + # ) + # await send_to_channel(self.bot, 'pd-network-news', embed=embed) + # + # # Gauntlet results and reward + # if gauntlet_team is not None: + # await gauntlets.post_result( + # int(this_game.game_type.split('-')[3]), + # is_win=winning_team['gmid'] == gauntlet_team['gmid'], + # this_team=gauntlet_team, + # bot=self.bot, + # channel=interaction.channel + # ) + # + # this_run = await db_get('gauntletruns', object_id=int(this_game.game_type.split('-')[3])) + # if this_run['losses'] == 2: + # await send_to_channel( + # bot=self.bot, + # channel_name='pd-network-news', + # content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the ' + # f'{this_run["gauntlet"]["name"]} gauntlet.', + # embed=None + # ) + # + # patch_game(this_game.id, active=False) + # + # logging.info(f'Game {this_game.id} is complete') + # if gauntlet_team is None: + # await interaction.edit_original_response( + # content=f'Good game! Go share the highlights in ' + # f'{get_channel(interaction, "pd-news-ticker").mention}!' + # ) + @app_commands.command( name='read-lineup', description='Import a saved lineup directly from the team sheet for PD games' diff --git a/db_calls_gameplay.py b/db_calls_gameplay.py index 189b9ed..a4c7506 100644 --- a/db_calls_gameplay.py +++ b/db_calls_gameplay.py @@ -109,6 +109,24 @@ def get_sba_team_by_owner(season, owner_id): # return pd_await db_get('cards', object_id=card_id, none_okay=False) +class DecisionModel(pydantic.BaseModel): + game_id: int + season: int + week: int + pitcher_id: int + pitcher_team_id: int + win: int = 0 + loss: int = 0 + hold: int = 0 + is_save: int = 0 + is_start: bool = False + b_save: int = 0 + irunners: int = 0 + irunners_scored: int = 0 + rest_ip: float = 0 + rest_required: int = 0 + + class BaseModel(Model): class Meta: database = db @@ -810,6 +828,7 @@ class Play(BaseModel): game = ForeignKeyField(Game) play_num = IntegerField() batter = ForeignKeyField(Lineup) + batter_pos = CharField(default='DH') pitcher = ForeignKeyField(Lineup, null=True) on_base_code = IntegerField() inning_half = CharField() @@ -818,6 +837,7 @@ class Play(BaseModel): starting_outs = IntegerField() away_score = IntegerField() home_score = IntegerField() + on_first = ForeignKeyField(Lineup, null=True) on_first_final = IntegerField(null=True) on_second = ForeignKeyField(Lineup, null=True) @@ -825,9 +845,11 @@ class Play(BaseModel): on_third = ForeignKeyField(Lineup, null=True) on_third_final = IntegerField(null=True) batter_final = IntegerField(null=True) + pa = IntegerField(default=0) ab = IntegerField(default=0) - # run = IntegerField(null=True) + run = IntegerField(default=0) + e_run = IntegerField(default=0) hit = IntegerField(default=0) rbi = IntegerField(default=0) double = IntegerField(default=0) @@ -846,6 +868,10 @@ class Play(BaseModel): sb = IntegerField(default=0) cs = IntegerField(default=0) outs = IntegerField(default=0) + + wpa = FloatField(default=0.0) + re24 = FloatField(default=0.0) + catcher = ForeignKeyField(Lineup, null=True) defender = ForeignKeyField(Lineup, null=True) runner = ForeignKeyField(Lineup, null=True) @@ -876,6 +902,8 @@ class StratPlay: starting_outs: int away_score: int home_score: int + batter_pos: str = None + on_first: StratLineup = None on_first_final: int = None on_second: StratLineup = None @@ -883,9 +911,11 @@ class StratPlay: on_third: StratLineup = None on_third_final: int = None batter_final: int = None + pa: int = 0 ab: int = 0 - # run: int = 0 + run: int = 0 + e_run: int = 0 hit: int = 0 rbi: int = 0 double: int = 0 @@ -904,9 +934,14 @@ class StratPlay: sb: int = 0 cs: int = 0 outs: int = 0 + + wpa: float = 0.0 + re24: float = 0.0 + catcher: StratLineup = None defender: StratLineup = None runner: StratLineup = None + check_pos: str = None error: int = 0 wild_pitch: int = 0 @@ -1171,6 +1206,31 @@ def get_last_inning_end_play(game_id, inning_half, inning_num): return return_play +def get_dbready_plays(game_id: int, db_game_id: int): + all_plays = Play.select().where(Play.game_id == game_id) + prep_plays = [model_to_dict(x) for x in all_plays] + db.close() + + for x in prep_plays: + x['pitcher_id'] = x['pitcher']['player_id'] + x['batter_id'] = x['batter']['player_id'] + x['batter_team_id'] = x['batter']['team_id'] + x['pitcher_team_id'] = x['pitcher']['team_id'] + if x['catcher'] is not None: + x['catcher_id'] = x['catcher']['player_id'] + x['catcher_team_id'] = x['catcher']['team_id'] + if x['defender'] is not None: + x['defender_id'] = x['defender']['player_id'] + x['defender_team_id'] = x['defender']['team_id'] + if x['runner'] is not None: + x['runner_id'] = x['runner']['player_id'] + x['runner_team_id'] = x['runner']['team_id'] + x['game_id'] = db_game_id + + logging.debug(f'all_plays:\n\n{prep_plays}\n') + return prep_plays + + class Bullpen(BaseModel): ai_team_id = IntegerField() closer_id = IntegerField() @@ -1993,7 +2053,7 @@ def get_pitching_stats(game_id, lineup_id: int = None, team_id: int = None): return return_pitchers -def get_pitching_decisions(game: StratGame): +def get_pitching_decisions(game: StratGame, db_game_id: int): # is_win, is_hold, is_loss = False, False, False # away_lineups = get_team_lineups(game.id, game.away_team_id) # home_lineups = get_team_lineups(game.id, game.home_team_id) @@ -2015,6 +2075,25 @@ def get_pitching_decisions(game: StratGame): gs.extend([away_pitcher.card_id, home_pitcher.card_id]) logging.debug(f'SPs: {away_pitcher} / {home_pitcher}') + decisions = { + away_pitcher.player_id: DecisionModel( + game_id=db_game_id, + season=game.season, + week=game.week_num, + pitcher_id=away_pitcher.player_id, + pitcher_team_id=away_pitcher.team_id, + is_start=True + ), + home_pitcher.player_id: DecisionModel( + game_id=db_game_id, + season=game.season, + week=game.week_num, + pitcher_id=home_pitcher.player_id, + pitcher_team_id=home_pitcher.team_id, + is_start=True + ) + } # { : DecisionModel } + for x in Play.select().where(Play.game_id == game.id): logging.debug(f'checking play num {x.play_num}') if x.inning_half == 'Top' and home_pitcher != x.pitcher: @@ -2108,6 +2187,36 @@ def get_pitching_decisions(game: StratGame): b_save.append(save.card_id) save = None + if home_pitcher.player_id not in decisions: + decisions[home_pitcher.player_id] = DecisionModel( + game_id=db_game_id, + season=game.season, + week=game.week_num, + pitcher_id=home_pitcher.player_id, + pitcher_team_id=home_pitcher.team_id + ) + + if away_pitcher.player_id not in decisions: + decisions[away_pitcher.player_id] = DecisionModel( + game_id=db_game_id, + season=game.season, + week=game.week_num, + pitcher_id=away_pitcher.player_id, + pitcher_team_id=away_pitcher.team_id + ) + + decisions[winner.player_id].win = 1 + decisions[loser.player_id].loss = 1 + if save is not None: + decisions[save.player_id].is_save = 1 + + for x in holds: + decisions[x.player_id].hold = 1 + for x in b_save: + decisions[x.player_id].b_save = 1 + + return [x.dict() for x in decisions.values()] + logging.debug(f'\n\nWin: {winner}\nLose: {loser}\nSave: {save}\nBlown Save: {b_save}\nHolds: {holds}') return { 'winner': winner.card_id, @@ -2153,7 +2262,7 @@ def get_pitching_decisions(game: StratGame): # if next_p_first.away_score < next_p_first.home_score: -def get_final_scorebug(away_team, home_team, away_stats, home_stats): +def get_final_scorebug(away_team, home_team, away_score, home_score): return f'```' \ f'Team | R | H | E |\n' \ f'{away_team["abbrev"].replace("Gauntlet-", ""): <4} | {away_stats["score"]: >2} | ' \