diff --git a/cogs/gameplay_legacy.py b/cogs/gameplay_legacy.py deleted file mode 100644 index d4d80db..0000000 --- a/cogs/gameplay_legacy.py +++ /dev/null @@ -1,4723 +0,0 @@ -import asyncio -import logging -import discord -import math -import os - -from in_game import ai_manager - -import dice -import gauntlets -from discord import app_commands -from discord.app_commands import Choice -from discord.ext import commands, tasks -from peewee import IntegrityError -from typing import Literal, Optional - -from dice import sa_fielding_roll_legacy -from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, IMAGES, \ - get_pos_abbrev, SBA_COLOR, get_roster_lineups, give_packs, send_to_channel, \ - get_channel, team_role, get_cal_user, ButtonOptions, get_ratings_guide, \ - get_team_by_owner, player_desc, player_pcard, player_bcard, get_team_embed, Confirm, get_sheets, Dropdown, \ - SELECT_CARDSET_OPTIONS, DropdownView -from in_game.ai_manager import check_pitching_sub -from in_game.game_helpers import single_onestar, single_wellhit, double_twostar, double_threestar, triple, \ - runner_on_first, runner_on_second, runner_on_third, gb_result_1, gb_result_2, gb_result_3, gb_result_4, \ - gb_result_5, gb_result_6, gb_result_7, gb_result_8, gb_result_9, gb_result_10, gb_result_11, gb_result_12, \ - gb_result_13, gb_decide, show_outfield_cards, legal_check, get_pitcher -from api_calls import db_get, db_patch, db_post, db_delete, get_team_by_abbrev -from db_calls_gameplay import StratGame, StratPlay, post_game, patch_game, get_game_team, post_lineups, make_sub, get_player, player_link, get_team_lineups, \ - 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_pitching_decisions, get_or_create_bullpen, get_active_games, patch_lineup, \ - get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs, get_dbready_plays - - -logger = logging.getLogger('discord_app') - - -class Gameplay(commands.Cog): - def __init__(self, bot): - self.bot = bot - self.batter_ratings = None - self.pitcher_ratings = None - self.live_scoreboard.start() - - @tasks.loop(minutes=3) - async def live_scoreboard(self): - guild = self.bot.get_guild(int(os.environ.get('GUILD_ID'))) - score_channel = discord.utils.get(guild.text_channels, name='live-pd-scores') - player_role = discord.utils.get(guild.roles, name=PD_PLAYERS_ROLE_NAME) - - active_games = get_active_games(6) - if len(active_games) == 0: - await score_channel.set_permissions(player_role, read_messages=False) - return - - try: - embed = get_team_embed('Live Scoreboard') - valid_scores = False - for x in active_games: - await asyncio.sleep(1) - gs = await self.get_game_state(x) - if not gs['error']: - valid_scores = True - channel = guild.get_channel(gs["channel_id"]) - g_message = gs['scorebug'] - g_message += f'Pitcher: {gs["pitcher"]["p_name"]}\n' \ - f'Batter: {gs["batter"]["p_name"]}\n' \ - f'Location: {channel.mention if channel is not None else "Your Butt"}\n' \ - f'-------------------------' - gt_string = 'Unlimited' - if x.game_type == 'minor-league': - gt_string = 'Minor League' - elif x.game_type == 'major-league': - gt_string = 'Major League' - elif x.game_type == 'hall-of-fame': - gt_string = 'Hall of Fame' - elif 'gauntlet' in x.game_type: - gt_string = 'Gauntlet' - elif x.game_type == 'flashback': - gt_string = 'Flashback' - elif 'exhibition' in x.game_type: - gt_string = 'Exhibition' - embed.add_field( - name=f'{gs["away_team"]["sname"]} @ {gs["home_team"]["sname"]} - {gt_string}', - value=g_message, - inline=False - ) - - if valid_scores: - async for message in score_channel.history(limit=25): - await message.delete() - - await score_channel.set_permissions(player_role, read_messages=True) - await score_channel.send(content=None, embed=embed) - else: - await score_channel.set_permissions(player_role, read_messages=False) - return - except Exception as e: - logger.error(f'Could not update live_scoreboard: {e}') - - @live_scoreboard.before_loop - async def before_live_scoreboard(self): - await self.bot.wait_until_ready() - - @tasks.loop(hours=36) - async def update_ratings_guides(self): - guild = self.bot.get_guild(int(os.environ.get('GUILD_ID'))) - if not guild: - logger.error(f'Cannot access guild; pausing ratings guide for 20 seconds') - await asyncio.sleep(20) - guild = self.bot.get_guild(int(os.environ.get('GUILD_ID'))) - if not guild: - logger.error(f'Still cannot access guild; trying again in 1 minutes') - await asyncio.sleep(60) - guild = self.bot.get_guild(int(os.environ.get('GUILD_ID'))) - if not guild: - logger.error(f'Still cannot access guild; dueces') - return - - data = get_ratings_guide(get_sheets(self.bot)) - if data['valid']: - self.batter_ratings = data['batter_ratings'] - self.pitcher_ratings = data['pitcher_ratings'] - else: - logger.error(f'gameplay - pulled bad ratings guide data') - - async def cog_command_error(self, ctx, error): - 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[: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 = '●' - unoccupied = '○' - - first_base = unoccupied if not curr_play.on_first else occupied - second_base = unoccupied if not curr_play.on_second else occupied - third_base = unoccupied if not curr_play.on_third else occupied - half = '▲' if curr_play.inning_half == 'Top' else '▼' - if curr_play.game.active: - inning = f'{half} {curr_play.inning_num}' - outs = f'{curr_play.starting_outs} Out{"s" if curr_play.starting_outs != 1 else ""}' - else: - inning = f'F/{curr_play.inning_num if curr_play.inning_half == "Bot" else curr_play.inning_num - 1}' - outs = '' - - game_string = f'```\n' \ - f'{away_team["abbrev"].replace("Gauntlet-", ""): ^4}{curr_play.away_score: ^3} {second_base}' \ - f'{inning: >10}\n' \ - f'{home_team["abbrev"].replace("Gauntlet-", ""): ^4}{curr_play.home_score: ^3} {third_base} ' \ - f'{first_base}{outs: >8}\n```' - - return game_string - - async def post_rewards(self, winning_team: dict, losing_team: dict, this_game: StratGame): - wr_query = await db_get( - 'gamerewards', params=[('name', f'{"Short" if this_game.short_game else "Full"} Game Win')]) - lr_query = await db_get( - 'gamerewards', params=[('name', f'{"Short" if this_game.short_game else "Full"} Game Loss')]) - if not wr_query['count'] or not lr_query['count']: - raise KeyError(f'Game Rewards were not found. Leaving this game active.') - - human_team = winning_team if losing_team['is_ai'] else losing_team - ai_team = winning_team if winning_team['is_ai'] else losing_team - - win_reward = wr_query['gamerewards'][0] - loss_reward = lr_query['gamerewards'][0] - win_string = f'1x {win_reward["pack_type"]["name"]} Pack\n' - - # Post Team Choice packs - if this_game.ai_team is not None and not this_game.short_game and 'gauntlet' not in this_game.game_type and \ - losing_team['is_ai']: - g_query = await db_get( - 'games', - params=[ - ('team1_id', human_team['id']), ('game_type', this_game.game_type), ('season', this_game.season) - ] - ) - wins = 0 - for x in g_query['games']: - if (x['away_score'] > x['home_score'] and x['away_team']['id'] == human_team['id']) or ( - x['home_score'] > x['away_score'] and x['home_team']['id'] == human_team['id']): - wins += 1 - - async def post_tc_pack(): - await db_post( - 'packs/one', - payload={ - 'team_id': human_team['id'], - 'pack_type_id': 8, - 'pack_team_id': losing_team['id'] - } - ) - - if g_query['count'] > 0: - if this_game.game_type == 'minor-league' and wins % 6 == 0: - await post_tc_pack() - win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n' - elif this_game.game_type == 'major-league' and wins % 4 == 0: - await post_tc_pack() - win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n' - elif this_game.game_type == 'hall-of-fame' and wins % 2 == 0: - await post_tc_pack() - win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n' - - win_string += f'{win_reward["money"]}₼\n' - loss_string = f'{loss_reward["money"]}₼\n' - - # Post rewards - if 'gauntlet' in this_game.game_type: - if 'Gauntlet' in winning_team['abbrev']: - t_query = await db_get('teams', params=[('abbrev', winning_team['abbrev'].split('-')[1])]) - winning_team = t_query['teams'][0] - if 'Gauntlet' in losing_team['abbrev']: - t_query = await db_get('teams', params=[('abbrev', losing_team['abbrev'].split('-')[1])]) - losing_team = t_query['teams'][0] - - await give_packs(winning_team, num_packs=1, pack_type=win_reward['pack_type']) - await db_post(f'teams/{winning_team["id"]}/money/{win_reward["money"]}') - await db_post(f'teams/{losing_team["id"]}/money/{loss_reward["money"]}') - - data = { - 'win_string': win_string, - 'loss_string': loss_string - } - - return data - - async def get_game_state(self, game: StratGame) -> dict: - 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) - - curr_play = get_current_play(game.id) - if curr_play is None: - away_lineup = await get_team_lineups(game.id, game.away_team_id) - home_lineup = await get_team_lineups(game.id, game.home_team_id) - logger.info(f'away_lineup: {away_lineup}') - logger.info(f'home_lineup: {home_lineup}') - - if len(away_lineup) < 200 or len(home_lineup) < 200: - game_state = { - 'error': True, - 'away_lineup': away_lineup, - 'home_lineup': home_lineup, - 'away_team': away_team, - 'home_team': home_team - } - logger.error(f'One ore more lineups not submitted in Game {game.id}\n\ngame_state: {game_state}') - return game_state - else: - logger.info(f'looking for home ({game.home_team_id}) pitcher in Game {game.id}') - pitcher = get_one_lineup(game.id, team_id=game.home_team_id, position='P') - logger.debug(f'pitcher: {pitcher}') - curr_play = post_play({ - 'game_id': game.id, - 'play_num': 1, - 'batter_id': get_one_lineup(game.id, team_id=game.away_team_id, batting_order=1).id, - 'pitcher_id': pitcher.id if pitcher else None, - 'on_base_code': 0, - 'inning_half': 'Top', - 'inning_num': 1, - 'batting_order': 1, - 'starting_outs': 0, - 'away_score': 0, - 'home_score': 0 - }) - - game_state = {'error': False, 'curr_play': curr_play, 'away_team': away_team, 'home_team': home_team} - - scorebug = self.get_scorebug(home_team, away_team, game_state['curr_play']) - game_state['scorebug'] = scorebug - - batter = await get_player(game, game_state['curr_play'].batter) - litmus = 0 - try: - if not game_state['curr_play'].pitcher: - p_search = get_one_lineup( - game.id, - team_id=game.away_team_id if game_state['curr_play'].inning_half == 'Bot' else game.home_team_id, - position='P' - ) - if p_search: - patch_play(game_state['curr_play'].id, pitcher_id=p_search.id) - pitcher = await get_player(game, game_state['curr_play'].pitcher) - litmus = 1 - catcher = await get_player( - game, - get_one_lineup( - game.id, - team_id=game.away_team_id if game_state['curr_play'].inning_half == 'Bot' else game.home_team_id, - position='C' - ) - ) - except Exception as e: - logger.error(f'ERROR: {e} / TYPE: {type(e)}') - away_lineup = await get_team_lineups(game.id, game.away_team_id) - home_lineup = await get_team_lineups(game.id, game.home_team_id) - if litmus == 0: - error_message = f'Please sub in a pitcher to continue' - else: - error_message = f'Please sub in a catcher to continue' - - game_state['error'] = True - game_state['error_message'] = error_message - game_state['away_lineup'] = away_lineup - game_state['home_lineup'] = home_lineup - return game_state - - game_state['batter'] = batter - game_state['pitcher'] = pitcher - game_state['catcher'] = catcher - game_state['channel_id'] = game.channel_id - - if curr_play.inning_half == 'Top': - game_state['pitcher']['team'] = home_team - game_state['catcher']['team'] = home_team - game_state['batter']['team'] = away_team - else: - game_state['pitcher']['team'] = away_team - game_state['catcher']['team'] = away_team - game_state['batter']['team'] = home_team - logger.debug(f'game_state: {game_state}') - - return game_state - - async def initialize_play_plus_embed(self, game: StratGame, full_length=True, for_liveboard=False): - game_state = await self.get_game_state(game) - - logger.debug(f'game_state: {game_state}') - - gt_string = ' - Unlimited' - if game.game_type == 'minor-league': - gt_string = ' - Minor League' - elif game.game_type == 'major-league': - gt_string = ' - Major League' - elif game.game_type == 'hall-of-fame': - gt_string = ' - Hall of Fame' - elif 'gauntlet' in game.game_type: - gt_string = ' - Gauntlet' - elif 'flashback' in game.game_type: - gt_string = ' - Flashback' - elif 'exhibition' in game.game_type: - gt_string = ' - Exhibition' - - if game_state['error']: - embed = discord.Embed( - title='Current Lineups', - color=int(SBA_COLOR, 16) - ) - embed.add_field(name='Away Team', - value=game_state['away_lineup'] if game_state['away_lineup'] else 'None, yet') - embed.add_field(name='Home Team', - value=game_state['home_lineup'] if game_state['home_lineup'] else 'None, yet') - if 'error_message' in game_state: - embed.set_footer(text=game_state['error_message'], icon_url=IMAGES['logo']) - - return embed - - logger.debug(f'no errors') - pitching_sub = None - ai_note = '' - gm_name = '' - fatigue = await ai_manager.is_pitcher_fatigued(game_state['curr_play']) - logger.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']]: - logger.debug(f'Checking AI stuff') - - # AI Team is pitching - if game_state['pitcher']['team']['is_ai']: - if fatigue: - pitching_sub = await check_pitching_sub(game_state['curr_play'], game_state['pitcher']['team']) - if pitching_sub is not None: - game_state = await self.get_game_state(game) - - ai_data = await ai_manager.pitching_ai_note(game_state['curr_play'], game_state['pitcher']) - logger.debug(f'ai_data: {ai_data}') - ai_note = ai_data['note'] - gm_name = ai_data['gm_name'] - - # AI Team is batting - if game_state['batter']['team']['is_ai']: - # embed.set_thumbnail(url=player_pcard(game_state["pitcher"])) - ai_data = ai_manager.batting_ai_note(game_state['curr_play'], game_state['batter']) - ai_note = ai_data['note'] - gm_name = ai_data['gm_name'] - - if pitching_sub is not None or (fatigue and pitching_sub is None) or abs( - game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10: - color = discord.Colour.red() - else: - color = int(SBA_COLOR, 16) - - embed = discord.Embed( - title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}', - color=color - ) - logger.info(f'got embed') - - footer_text = f'Paper Dynasty Season {PD_SEASON}' - if game.short_game: - footer_text += f' - Reminder: all pitchers have POW(1) in 3-inning games' - embed.set_footer(text=footer_text, icon_url=IMAGES['logo']) - - embed.add_field(name='Game State', value=game_state['scorebug'], inline=False) - embed.set_thumbnail(url=player_pcard(game_state['pitcher'])) - - logger.info(f'check mercy') - if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10: - embed.description = '***Mercy rule in effect***' - - logger.info(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}' - - logger.info(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] - batter_string += f'\n{b_s["pl_hit"]}-{b_s["pl_ab"]}' - for num, stat in [ - (b_s['pl_double'], '2B'), (b_s['pl_triple'], '3B'), (b_s['pl_homerun'], 'HR'), (b_s['pl_rbi'], 'RBI'), - (b_s['pl_bb'], 'BB'), (b_s['pl_hbp'], 'HBP'), (b_s['pl_ibb'], 'IBB'), (b_s['pl_so'], 'K'), - (b_s['pl_gidp'], 'GIDP'), (b_s['pl_bpfo'], 'BPFO'), (b_s['pl_bplo'], 'BPLO') - ]: - if num: - batter_string += f', {num if num > 1 else ""}{" " if num > 1 else ""}{stat}' - - logger.info(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] - pitcher_string += f'\n{math.floor(p_s["pl_outs"]/3)}.{p_s["pl_outs"] % 3} IP' - for num, stat in [ - (p_s['pl_runs'], 'R'), (p_s['pl_hit'], 'H'), (p_s['pl_homerun'], 'HR'), (p_s['pl_so'], 'K'), - (p_s['pl_bb'], 'BB'), (p_s['pl_hbp'], 'HBP'), (p_s['pl_wild_pitch'], 'WP'), (p_s['pl_balk'], 'BK'), - ]: - if num: - pitcher_string += f', {num} {stat}' - if stat == 'R' and num != p_s['pl_eruns']: - pitcher_string += f', {p_s["pl_eruns"]} ER' - if fatigue and pitching_sub is None: - pitcher_string += f'\n***F A T I G U E D***' - - logger.info(f'set embed pitcher/batter') - 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'])) - - logger.info(f'get baserunners') - baserunner_string = '' - if game_state['curr_play'].on_first: - runner = await get_player(game, game_state['curr_play'].on_first) - baserunner_string += f'On First: {player_link(game, runner)}\n' - if game_state['curr_play'].on_second: - runner = await get_player(game, game_state['curr_play'].on_second) - baserunner_string += f'On Second: {player_link(game, runner)}\n' - if game_state['curr_play'].on_third: - runner = await get_player(game, game_state['curr_play'].on_third) - baserunner_string += f'On Third: {player_link(game, runner)}\n' - - logger.info(f'set baserunners') - if len(baserunner_string) > 0: - embed.add_field(name=' ', value=' ', inline=False) - embed.add_field( - name='Baserunners', value=baserunner_string - ) - embed.add_field( - name='Catcher', value=f'{player_link(game, game_state["catcher"])}' - ) - else: - embed.add_field( - name='Baserunners', value='None', inline=False - ) - - if len(ai_note) > 0: - embed.add_field( - name=f'{gm_name} will...', - value=ai_note, - inline=False - ) - - if pitching_sub is not None: - embed.add_field( - name='SUBSTITUTION', - value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in ' - f'**{player_desc(pitching_sub)}** to pitch' - ) - - logger.info(f'if not full length: return embed: {embed}') - if not full_length: - return embed - - away_lineup = await get_team_lineups(game.id, game.away_team_id) - home_lineup = await get_team_lineups(game.id, game.home_team_id) - embed.add_field(name=f'{game_state["away_team"]["abbrev"]} Lineup', value=away_lineup) - embed.add_field(name=f'{game_state["home_team"]["abbrev"]} Lineup', value=home_lineup) - return embed - - async def groundballs_old( - self, interaction, this_game, this_play: StratPlay, groundball_type: str, comp_play: bool = True): - batter_to_base = None - bases = ['third', 'second', 'first'] - - if this_play.starting_outs == 2 or this_play.on_base_code == 0: - patch_play(this_play.id, pa=1, ab=1, outs=1) - - else: - if groundball_type == 'a': - if this_play.on_base_code == 1: - patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2) - - elif this_play.on_base_code == 4: - if this_play.starting_outs == 1: - patch_play(this_play.id, pa=1, ab=1, outs=2) - else: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is the double play at second and first?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - patch_play( - this_play.id, - pa=1, - ab=1, - outs=2, - on_second_final=3, - on_first_final=False, - ) - - else: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is the double play at third and second?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - patch_play( - this_play.id, - pa=1, - ab=1, - outs=2, - on_second_final=False, - on_first_final=False - ) - batter_to_base = 1 - - else: - await question.edit( - content=f'Hmm...not sure what else this could be. If you expected a different ' - f'result, let Cal know.', - view=None - ) - return - - elif this_play.on_base_code == 7: - if this_play.starting_outs == 1: - patch_play(this_play.id, pa=1, ab=1, outs=2) - else: - runner = await get_player(this_game, this_play.on_third) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {runner["p_name"]} out on the home-to-first double play?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - advance_runners(this_play.id, 1) - patch_play(this_play.id, on_third_final=False, pa=1, ab=1, outs=2, rbi=0) - else: - await question.delete() - advance_runners(this_play.id, 1) - patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2, rbi=0) - - else: - num_outs = 1 - - for count, x in enumerate([this_play.on_third, this_play.on_second, this_play.on_first]): - if x: - runner = await get_player(this_game, x) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from {bases[count]} on the play?', view=view - ) - await view.wait() - - num_bases = 0 - if view.value: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} thrown out?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=False) - elif count == 1: - patch_play(this_play.id, on_second_final=False) - else: - patch_play(this_play.id, on_first_final=False) - num_outs += 1 - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=4) - elif count == 1: - patch_play(this_play.id, on_second_final=3) - else: - patch_play(this_play.id, on_first_final=2) - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=3) - elif count == 1: - patch_play(this_play.id, on_second_final=2) - else: - patch_play(this_play.id, on_first_final=1) - - if this_play.on_third: - batter = await get_player(this_game, this_play.batter) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {batter["p_name"]} out at first?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - else: - await question.delete() - num_outs -= 1 - batter_to_base = 1 - - patch_play(this_play.id, pa=1, ab=1, outs=num_outs) - if num_outs + this_play.starting_outs == 3: - advance_runners(this_play.id, 0) - - elif groundball_type == 'b': - if this_play.on_base_code == 3 or this_play.on_base_code == 6 or this_play.on_base_code == 2: - if this_play.on_base_code == 2: - runner = await get_player(this_game, this_play.on_second) - from_base = 'second' - else: - runner = await get_player(this_game, this_play.on_third) - from_base = 'third' - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from {from_base} on the play?', view=view - ) - await view.wait() - - if view.value: - advance_runners(this_play.id, 1) - - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} thrown out?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if from_base == 'third': - patch_play(this_play.id, on_third_final=False) - - # from second - else: - patch_play(this_play.id, on_second_final=False) - else: - await question.delete() - else: - await question.delete() - advance_runners(this_play.id, 0) - - patch_play(this_play.id, pa=1, ab=1, outs=1) - - elif this_play.on_base_code == 1 or this_play.on_base_code == 4: - advance_runners(this_play.id, 1) - patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=1) - batter_to_base = 1 - - else: - num_outs = 0 - for count, x in enumerate([this_play.on_third, this_play.on_second, this_play.on_first]): - if x: - runner = await get_player(this_game, x) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from {bases[count]} on the play?', view=view - ) - await view.wait() - - num_bases = 0 - if view.value: - await question.delete() - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} thrown out?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=False) - elif count == 1: - patch_play(this_play.id, on_second_final=False) - else: - patch_play(this_play.id, on_first_final=False) - num_outs += 1 - else: - await question.delete() - advance_one_runner(this_play.id, from_base=3 - count, num_bases=1) - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=3) - elif count == 1: - patch_play(this_play.id, on_second_final=2) - else: - patch_play(this_play.id, on_first_final=1) - - if num_outs == 0: - batter = await get_player(this_game, this_play.batter) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {batter["p_name"]} out at first?', view=view - ) - - await view.wait() - - if view.value: - await question.delete() - num_outs += 1 - else: - await question.delete() - await interaction.edit_original_response( - content=f'Okay so it wasn\'t a gb B then? Go ahead and log a new play.' - ) - patch_play(this_play.id, locked=False) - return - else: - batter_to_base = 1 - - patch_play(this_play.id, pa=1, ab=1, outs=num_outs) - - elif groundball_type == 'c': - if this_play.on_base_code == 7: - runner = await get_player(this_game, this_play.on_third) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {runner["p_name"]} forced out at home?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - advance_runners(this_play.id, 1) - patch_play(this_play.id, on_third_final=False, pa=1, ab=1, outs=1, rbi=0) - batter_to_base = 1 - else: - await question.delete() - advance_runners(this_play.id, 1) - patch_play(this_play.id, pa=1, ab=1, outs=1) - - elif this_play.on_third: - num_outs = 0 - for count, x in enumerate([this_play.on_third, this_play.on_second, this_play.on_first]): - if x: - runner = await get_player(this_game, x) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from {bases[count]} on the play?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} thrown out?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=False) - elif count == 1: - patch_play(this_play.id, on_second_final=False) - else: - patch_play(this_play.id, on_first_final=False) - num_outs += 1 - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=4) - elif count == 1: - patch_play(this_play.id, on_second_final=3) - else: - patch_play(this_play.id, on_first_final=2) - - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=3) - elif count == 1: - patch_play(this_play.id, on_second_final=2) - else: - patch_play(this_play.id, on_first_final=1) - - if not num_outs: - num_outs += 1 - - logger.debug(f'should be patching the gb C now...') - patch_play(this_play.id, pa=1, ab=1, outs=num_outs) - - else: - advance_runners(this_play.id, 1) - patch_play(this_play.id, pa=1, ab=1, outs=1) - - if comp_play: - complete_play(this_play.id, batter_to_base=batter_to_base) - - async def groundballs( - self, interaction, this_game, this_play: StratPlay, groundball_type: str, comp_play: bool = True): - batter_to_base = None - - if this_play.starting_outs == 2 or this_play.on_base_code == 0: - patch_play(this_play.id, pa=1, ab=1, outs=1) - - elif this_play.starting_outs == 1 and groundball_type == 'a' and this_play.on_base_code == 1: - patch_play(this_play.id, pa=1, ab=1, outs=2, on_first_final=False) - - else: - playing_in = False - if runner_on_third(this_play): - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the defender playing in?', view=view - ) - await view.wait() - - if view.value: - playing_in = True - else: - playing_in = False - - await question.delete() - logger.info(f'playing_in: {playing_in} / obc: {this_play.on_base_code} / gb_type: {groundball_type}') - - if not playing_in: - if groundball_type == 'a': - if this_play.on_base_code == 0: - batter_to_base = gb_result_1(this_play) - - elif this_play.on_base_code in [1, 4, 5, 7]: - batter_to_base = gb_result_2(this_play) - - elif this_play.on_base_code in [3, 6]: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the ball hit to either the 2B or SS?', view=view - ) - await view.wait() - - if view.value: - to_mif = True - else: - to_mif = False - await question.delete() - - batter_to_base = gb_result_5(this_play, to_mif) - - else: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the ball hit to either the 1B or 2B?', view=view - ) - await view.wait() - - if view.value: - to_right_side = True - else: - to_right_side = False - await question.delete() - batter_to_base = gb_result_6(this_play, to_right_side) - - elif groundball_type == 'b': - if this_play.on_base_code == 0: - batter_to_base = gb_result_1(this_play) - - elif this_play.on_base_code in [1, 4, 5, 7]: - batter_to_base = gb_result_4(this_play) - - elif this_play.on_base_code in [3, 6]: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the ball hit to either the 2B or SS?', view=view - ) - await view.wait() - - if view.value: - to_mif = True - else: - to_mif = False - await question.delete() - - batter_to_base = gb_result_5(this_play, to_mif) - - else: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the ball hit to either the 1B or 2B?', view=view - ) - await view.wait() - - if view.value: - to_right_side = True - else: - to_right_side = False - await question.delete() - batter_to_base = gb_result_6(this_play, to_right_side) - - else: - if this_play.on_base_code == 0: - batter_to_base = gb_result_1(this_play) - - else: - batter_to_base = gb_result_3(this_play) - - else: - if groundball_type == 'a': - if this_play.on_base_code == 7: - batter_to_base = gb_result_10(this_play) - else: - batter_to_base = gb_result_7(this_play) - - elif groundball_type == 'b': - if this_play.on_base_code == 7: - batter_to_base = gb_result_11(this_play) - elif this_play.on_base_code == 5: - batter_to_base = gb_result_9(this_play) - else: - batter_to_base = gb_result_1(this_play) - - else: - if this_play.on_base_code == 7: - batter_to_base = gb_result_11(this_play) - else: - batter_to_base = gb_result_8(this_play) - - if comp_play: - complete_play(this_play.id, batter_to_base=batter_to_base) - - async def flyballs(self, interaction, this_game, this_play, flyball_type, comp_play: bool = True): - num_outs = 1 - - if flyball_type == 'a': - patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1) - if this_play.starting_outs < 2: - advance_runners(this_play.id, 1) - if this_play.on_third: - patch_play(this_play.id, ab=0) - - elif flyball_type == 'b' or flyball_type == 'ballpark': - patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1, bpfo=1 if flyball_type == 'ballpark' else 0) - advance_runners(this_play.id, num_bases=0) - if this_play.starting_outs < 2 and this_play.on_third: - patch_play(this_play.id, ab=0, rbi=1) - advance_one_runner(this_play.id, from_base=3, num_bases=1) - - if this_play.starting_outs < 2 and this_play.on_second: - logger.debug(f'calling of embed') - await show_outfield_cards(interaction, this_play) - logger.debug(f'done with of embed') - - ai_hint = '' - if this_game.ai_team and ai_batting(this_game, this_play): - ai_hint = f'*The runner will {get_manager(this_game).tag_from_second(this_play.starting_outs + 1)}*' - runner = await get_player(this_game, this_play.on_second) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from second on the play?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - - view = ButtonOptions( - responders=[interaction.user], timeout=60, - labels=['Tagged Up', 'Hold at 2nd', 'Out at 3rd', None, None] - ) - question = await interaction.channel.send( - f'What was the result of {runner["p_name"]} tagging from second?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if view.value == 'Tagged Up': - advance_one_runner(this_play.id, from_base=2, num_bases=1) - elif view.value == 'Out at 3rd': - num_outs += 1 - patch_play(this_play.id, on_second_final=False, outs=num_outs) - else: - await question.delete() - else: - await question.delete() - - elif flyball_type == 'b?': - patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1) - advance_runners(this_play.id, num_bases=0) - if this_play.starting_outs < 2 and this_play.on_third: - logger.debug(f'calling of embed') - await show_outfield_cards(interaction, this_play) - logger.debug(f'done with of embed') - - ai_hint = '' - if ai_batting(this_game, this_play): - ai_hint = f'*The runner will {get_manager(this_game).tag_from_third(this_play.starting_outs + 1)}*' - runner = await get_player(this_game, this_play.on_third) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} sent from third on the play?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was {runner["p_name"]} thrown out?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - patch_play(this_play.id, on_third_final=False) - num_outs += 1 - patch_play(this_play.id, outs=num_outs) - else: - await question.delete() - advance_one_runner(this_play.id, from_base=3, num_bases=1) - else: - await question.delete() - - elif flyball_type == 'c': - patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1) - advance_runners(this_play.id, num_bases=0) - - if comp_play: - complete_play(this_play.id) - - group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game') - - @group_new_game.command(name='mlb-campaign', description='Start a new MLB Campaign game against an AI') - @app_commands.describe( - sp_card_id='Light gray number to the left of the pitcher\'s name on your depth chart') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def new_game_campaign_command( - self, interaction: discord.Interaction, - league: Literal['Minor League', 'Flashback', 'Major League', 'Hall of Fame'], - away_team_abbrev: str, home_team_abbrev: str, num_innings: Literal[9, 3], sp_card_id: int): - await interaction.response.defer() - - conflict = get_one_game(channel_id=interaction.channel.id, active=True) - if conflict: - await interaction.edit_original_response( - content=f'Ope. There is already a game going on in this channel. Please wait for it to complete ' - f'before starting a new one.') - return - - try: - if interaction.channel.category.name != 'Public Fields': - await interaction.response.send_message( - f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything ' - f'pops up?' - ) - return - except Exception as e: - logger.error(f'Could not check channel category: {e}') - - away_team = await get_team_by_abbrev(away_team_abbrev) - home_team = await get_team_by_abbrev(home_team_abbrev) - - if not away_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.' - ) - return - if not home_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.' - ) - return - - # if True in [away_team['is_ai'], home_team['is_ai']] and is_ranked: - # await interaction.edit_original_response( - # content=f'Sorry, ranked games can only be played against human teams. Run `/new-game` again with ' - # f'`is_ranked` set to False to play against the ' - # f'{away_team["sname"] if away_team["is_ai"] else home_team["sname"]}.' - # ) - # return - - for x in [away_team, home_team]: - if not x['is_ai']: - conflict = count_team_games(x['id']) - if conflict['count']: - await interaction.edit_original_response( - content=f'Ope. The {x["sname"]} are already playing over in ' - f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}' - ) - return - - current = await db_get('current') - week_num = current['week'] - # logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: {is_ranked}') - logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num}') - - if not away_team['is_ai'] and not home_team['is_ai']: - logger.error(f'MLB Campaign game between {away_team["abbrev"]} and {home_team["abbrev"]} has no AI') - await interaction.edit_original_response( - content=f'I don\'t see an AI team in this MLB Campaign game. Run `/new-game mlb-campaign` again with ' - f'an AI for a campaign game or `/new-game ` for a human game.' - ) - return - - ai_team = away_team if away_team['is_ai'] else home_team - human_team = away_team if home_team['is_ai'] else home_team - - if interaction.user.id not in [away_team['gmid'], home_team['gmid']]: - await interaction.edit_original_response( - content='You can only start a new game if you GM one of the teams.' - ) - return - - if 'Minor' in league: - league_name = 'minor-league' - elif 'Flashback' in league: - can_play = False - for x in interaction.user.roles: - if x.name == 'PD - Major League': - can_play = True - - if not can_play: - await interaction.edit_original_response( - content=f'Ope. Looks like you haven\'t completed the Minor League campaign, yet!\n\n' - f'To play **Flashback** games, you need to defeat all 30 MLB teams in the Minor League ' - f'campaign. You can see your progress with `/record`.\n\n' - f'If you have completed the Minor League campaign, go ping Cal to get your new role!') - return - league_name = 'flashback' - - elif 'Major' in league: - can_play = False - for x in interaction.user.roles: - if x.name == 'PD - Major League': - can_play = True - - if not can_play: - await interaction.edit_original_response( - content=f'Ope. Looks like you haven\'t received the **PD - Major League** role, yet!\n\n' - f'To play **Major League** games, you need to defeat all 30 MLB teams in the Minor League ' - f'campaign. You can see your progress with `/record`.\n\n' - f'If you have completed the Minor League campaign, go ping Cal to get your new role!') - return - league_name = 'major-league' - else: - can_play = False - for x in interaction.user.roles: - if x.name == 'PD - Hall of Fame': - can_play = True - - if not can_play: - await interaction.edit_original_response( - content=f'Ope. Looks like you haven\'t received the **PD - Hall of Fame** role, yet!\n\n' - f'To play **Hall of Fame** games, you need to defeat all 30 MLB teams in the Minor League ' - f'and Major League campaign. You can see your progress with `/record`.\n\n' - f'If you have completed the Major League campaign, go ping Cal to get your new role!') - return - league_name = 'hall-of-fame' - - this_game = post_game({ - 'away_team_id': away_team['id'], - 'home_team_id': home_team['id'], - 'week_num': week_num, - 'channel_id': interaction.channel.id, - 'active': True, - 'is_pd': True, - 'ranked': False, - 'season': current['season'], - 'short_game': True if num_innings == 3 else False, - 'game_type': league_name - }) - logger.info( - f'Game {this_game.id} ({league_name}) between {away_team_abbrev.upper()} and ' - f'{home_team_abbrev.upper()} is posted!' - ) - away_role = await team_role(interaction, away_team) - home_role = await team_role(interaction, home_team) - all_lineups = [] - - # Get Human SP - human_sp_card = await db_get(f'cards', object_id=sp_card_id) - - if human_sp_card['team']['id'] != human_team['id']: - logger.error( - f'Card_id {sp_card_id} does not belong to {human_team["abbrev"]} in Game {this_game.id}' - ) - patch_game(this_game.id, active=False) - await interaction.channel.send( - f'Uh oh. Card ID {sp_card_id} is {human_team["player"]["p_name"]} and belongs to ' - f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?') - return - - if this_game.game_type in ['major-league', 'hall-of-fame']: - l_check = await legal_check([human_sp_card['id']], 'ranked') - if not l_check['legal']: - patch_game(this_game.id, active=False) - await interaction.edit_original_response( - content=f'It looks like this is a Ranked Legal game and {player_desc(human_sp_card["player"])} is ' - f'not legal in Ranked. You can start a new game once you pick a new SP.' - ) - return - - if this_game.game_type == 'flashback': - l_check = await legal_check([human_sp_card['id']], 'flashback') - if not l_check['legal']: - patch_game(this_game.id, active=False) - await interaction.edit_original_response( - content=f'It looks like this is a Flashback game and {player_desc(human_sp_card["player"])} is ' - f'not legal in Flashback. You can start a new game once you pick a new SP.' - ) - return - - all_lineups.append({ - 'game_id': this_game.id, - 'team_id': human_team['id'], - 'player_id': human_sp_card['player']['player_id'], - 'card_id': sp_card_id, - 'position': 'P', - 'batting_order': 10, - 'after_play': 0 - }) - - # Get AI Starting Pitcher - try: - await interaction.edit_original_response( - content=f'Now to decide on a Starting Pitcher...' - ) - if ai_team['id'] == this_game.away_team_id: - patch_game(this_game.id, away_roster_num=69, ai_team='away') - else: - patch_game(this_game.id, home_roster_num=69, ai_team='home') - - # starter = starting_pitcher(ai_team, self.bot, True if home_team['is_ai'] else False) - starter = await ai_manager.get_starting_pitcher( - ai_team, - this_game.id, - True if home_team['is_ai'] else False, - league_name - ) - all_lineups.append(starter) - ai_sp = await db_get('players', object_id=starter['player_id']) - - this_card = await db_get(f'cards', object_id=starter['card_id']) - await interaction.channel.send( - content=f'The {ai_team["sname"]} are starting **{player_desc(this_card["player"])}**:\n\n' - f'{player_pcard(this_card["player"])}' - ) - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start an AI game with {ai_team["sname"]}: {e}') - await interaction.edit_original_response( - content=f'Looks like the {ai_team["sname"]} rotation didn\'t come through clearly. I\'ll sort ' - f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - return - - # Get AI Lineup - try: - await interaction.edit_original_response( - content=f'I am getting a lineup card from the {ai_team["sname"]}...' - ) - - logger.info(f'new-game - calling lineup for {ai_team["abbrev"]}') - batters = await ai_manager.build_lineup( - ai_team, this_game.id, league_name, sp_name=ai_sp['p_name'] - ) - all_lineups.extend(batters) - logger.info(f'new-game - got lineup for {ai_team["abbrev"]}') - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start an AI game with {ai_team["sname"]}: {e}') - await interaction.edit_original_response( - content=f'Looks like the {ai_team["sname"]} lineup card didn\'t come through clearly. I\'ll sort ' - f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - return - - logger.debug(f'Setting lineup for {ai_team["sname"]} in PD game') - logger.debug(f'lineups: {all_lineups}') - post_lineups(all_lineups) - - await interaction.channel.send( - content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - - @group_new_game.command(name='ranked', description='Start a new Ranked game against another human') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def new_game_ranked_command( - self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str, - num_innings: Literal[9, 3]): - await interaction.response.defer() - - conflict = get_one_game(channel_id=interaction.channel.id, active=True) - if conflict: - await interaction.edit_original_response( - content=f'Ope. There is already a game going on in this channel. Please wait for it to complete ' - f'before starting a new one.') - return - - try: - if interaction.channel.category.name != 'Public Fields': - await interaction.response.send_message( - f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything ' - f'pops up?' - ) - return - except Exception as e: - logger.error(f'Could not check channel category: {e}') - - away_team = await get_team_by_abbrev(away_team_abbrev) - home_team = await get_team_by_abbrev(home_team_abbrev) - - if not away_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.' - ) - return - if not home_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.' - ) - return - - if away_team['is_ai'] or home_team['is_ai']: - logger.error(f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI') - await interaction.edit_original_response( - content=f'Only human vs human games can be ranked - run `/new-game` again and double-check the ' - f'game type you want! If you have questions, feel free to post up in #paper-dynasty-chat' - ) - return - - for x in [away_team, home_team]: - if not x['is_ai']: - conflict = count_team_games(x['id']) - if conflict['count']: - await interaction.edit_original_response( - content=f'Ope. The {x["sname"]} are already playing over in ' - f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}' - ) - return - - current = await db_get('current') - week_num = current['week'] - logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: True') - - if interaction.user.id not in [away_team['gmid'], home_team['gmid']]: - await interaction.edit_original_response( - content='You can only start a new game if you GM one of the teams.' - ) - return - - this_game = post_game({ - 'away_team_id': away_team['id'], - 'home_team_id': home_team['id'], - 'week_num': week_num, - 'channel_id': interaction.channel.id, - 'active': True, - 'is_pd': True, - 'ranked': True, - 'season': current['season'], - 'short_game': True if num_innings == 3 else False, - 'game_type': 'ranked' - }) - logger.info( - f'Game {this_game.id} between {away_team_abbrev.upper()} and {home_team_abbrev.upper()} is posted!' - ) - away_role = await team_role(interaction, away_team) - home_role = await team_role(interaction, home_team) - - await interaction.channel.send( - content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - - @group_new_game.command(name='unlimited', description='Start a new Unlimited game against another human') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def new_game_unlimited_command( - self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str, - num_innings: Literal[9, 3]): - await interaction.response.defer() - - conflict = get_one_game(channel_id=interaction.channel.id, active=True) - if conflict: - await interaction.edit_original_response( - content=f'Ope. There is already a game going on in this channel. Please wait for it to complete ' - f'before starting a new one.') - return - - try: - if interaction.channel.category.name != 'Public Fields': - await interaction.response.send_message( - f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything ' - f'pops up?' - ) - return - except Exception as e: - logger.error(f'Could not check channel category: {e}') - - away_team = await get_team_by_abbrev(away_team_abbrev) - home_team = await get_team_by_abbrev(home_team_abbrev) - - if not away_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.' - ) - return - if not home_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.' - ) - return - - if away_team['is_ai'] or home_team['is_ai']: - logger.error(f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI') - await interaction.edit_original_response( - content=f'This command is for human v human games - run `/new-game` again and double-check the ' - f'game type you want! If you have questions, feel free to post up in #paper-dynasty-chat' - ) - return - - for x in [away_team, home_team]: - if not x['is_ai']: - conflict = count_team_games(x['id']) - if conflict['count']: - await interaction.edit_original_response( - content=f'Ope. The {x["sname"]} are already playing over in ' - f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}' - ) - return - - current = await db_get('current') - week_num = current['week'] - logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: True') - - if interaction.user.id not in [away_team['gmid'], home_team['gmid']]: - await interaction.edit_original_response( - content='You can only start a new game if you GM one of the teams.' - ) - return - - this_game = post_game({ - 'away_team_id': away_team['id'], - 'home_team_id': home_team['id'], - 'week_num': week_num, - 'channel_id': interaction.channel.id, - 'active': True, - 'is_pd': True, - 'ranked': False, - 'season': current['season'], - 'short_game': True if num_innings == 3 else False, - 'game_type': 'unlimited' - }) - logger.info( - f'Game {this_game.id} between {away_team_abbrev.upper()} and {home_team_abbrev.upper()} is posted!' - ) - away_role = await team_role(interaction, away_team) - home_role = await team_role(interaction, home_team) - - await interaction.channel.send( - content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - - @group_new_game.command(name='gauntlet', description='Start a new Gauntlet game against an AI') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def new_game_gauntlet_command( - self, interaction: discord.Interaction, event_name: Literal['2024 Season', 'Super Ultra Championship'], - sp_card_id: int): - await interaction.response.defer() - - conflict = get_one_game(channel_id=interaction.channel.id, active=True) - if conflict: - await interaction.edit_original_response( - content=f'Ope. There is already a game going on in this channel. Please wait for it to complete ' - f'before starting a new one.') - return - - try: - if interaction.channel.category.name != 'Public Fields': - await interaction.response.send_message( - f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything ' - f'pops up?' - ) - return - except Exception as e: - logger.error(f'Could not check channel category: {e}') - - current = await db_get('current') - week_num = current['week'] - - e_query = await db_get('events', params=[("name", event_name), ("active", True)]) - if e_query['count'] == 0: - await interaction.edit_original_response( - content=f'It looks like the {event_name} has ended! Cal should really remove it from this list.' - ) - return - this_event = e_query['events'][0] - - if interaction.user.id == 258104532423147520: - main_team = await get_team_by_abbrev('SKB') - else: - main_team = await get_team_by_owner(interaction.user.id) - team = await get_team_by_abbrev(f'Gauntlet-{main_team["abbrev"]}') - if not main_team: - await interaction.edit_original_response( - content=f'I don\'t see a team for you, yet. You can sign up with the `/newteam` command!' - ) - return - if not team: - await interaction.edit_original_response( - content=f'I don\'t see an active run for you. You can get started with the `/gauntlets start` command!' - ) - return - - conflict = count_team_games(team['id']) - if conflict['count']: - await interaction.edit_original_response( - content=f'Ope. The {team["sname"]} are already playing over in ' - f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}' - ) - return - - # Get Gauntlet run - r_query = await db_get( - 'gauntletruns', - params=[('team_id', team['id']), ('gauntlet_id', this_event['id']), ('is_active', True)] - ) - - if r_query['count'] == 0: - await interaction.edit_original_response( - content=f'I don\'t see an active run for you. If you would like to start a new one, run ' - f'`/gauntlets start {this_event["name"]}` and we can get you started in no time!' - ) - return - - this_run = r_query['runs'][0] - - # If not new or after draft, create new AI game - is_home = gauntlets.is_home_team(team, this_event, this_run) - opponent = await gauntlets.get_opponent(team, this_event, this_run) - if opponent is None: - await interaction.edit_original_response( - content=f'Yike. I\'m not sure who your next opponent is. {get_cal_user(interaction)} help plz!' - ) - return - else: - logger.info(f'opponent: {opponent}') - - game_code = gauntlets.get_game_code(team, this_event, this_run) - this_game = post_game({ - 'away_team_id': opponent['id'] if is_home else team['id'], - 'home_team_id': team['id'] if is_home else opponent['id'], - 'week_num': week_num, - 'channel_id': interaction.channel.id, - 'active': True, - 'is_pd': True, - 'ranked': False, - 'season': current['season'], - 'short_game': False, - 'game_type': game_code - }) - logger.info( - f'Game {this_game.id} between {team["abbrev"]} and {opponent["abbrev"]} is posted!' - ) - t_role = await team_role(interaction, main_team) - - all_lineups = [] - # Get Human SP - human_sp_card = await db_get(f'cards', object_id=sp_card_id) - - if human_sp_card['team']['id'] != team['id']: - logger.error( - f'Card_id {sp_card_id} does not belong to {team["abbrev"]} in Game {this_game.id}' - ) - await interaction.channel.send( - f'Uh oh. Card ID {sp_card_id} is {team["player"]["p_name"]} and belongs to ' - f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?') - return - - logger.info(f'Appending Human SP ({human_sp_card["player"]["p_name"]}) to all_lineups') - all_lineups.append({ - 'game_id': this_game.id, - 'team_id': team['id'], - 'player_id': human_sp_card['player']['player_id'], - 'card_id': sp_card_id, - 'position': 'P', - 'batting_order': 10, - 'after_play': 0 - }) - - # Get AI Starting Pitcher - try: - logger.info(f'Getting SP for {opponent["abbrev"]}') - await interaction.edit_original_response( - content=f'Now to decide on a Starting Pitcher...' - ) - if opponent['id'] == this_game.away_team_id: - patch_game(this_game.id, away_roster_num=69, ai_team='away') - else: - patch_game(this_game.id, home_roster_num=69, ai_team='home') - - starter = await gauntlets.get_starting_pitcher(opponent, this_game, this_event, this_run) - all_lineups.append(starter) - ai_sp = await db_get('players', object_id=starter['player_id']) - - this_card = await db_get(f'cards', object_id=starter['card_id']) - await interaction.channel.send( - content=f'The {opponent["sname"]} are starting **{player_desc(this_card["player"])}**:\n\n' - f'{this_card["player"]["image"]}' - ) - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start an AI game with {opponent["sname"]}: {e}') - await interaction.edit_original_response( - content=f'Looks like the {opponent["sname"]} rotation didn\'t come through clearly. I\'ll sort ' - f'this out with {opponent["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - return - - # Get AI Lineup - try: - await interaction.edit_original_response( - content=f'I am getting a lineup card from the {opponent["sname"]}...' - ) - - logger.info(f'new-game - calling lineup for {opponent["abbrev"]}') - batters = await gauntlets.build_lineup(opponent, this_game, this_event, ai_sp["p_name"]) - all_lineups.extend(batters) - logger.info(f'new-game-gauntlet - got lineup for {opponent["abbrev"]}') - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start a gauntlet game with {opponent["sname"]}: {e}') - await interaction.edit_original_response( - content=f'Looks like the {opponent["sname"]} lineup card didn\'t come through clearly. I\'ll sort ' - f'this out with {opponent["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - return - - logger.debug(f'Setting lineup for {opponent["sname"]} in PD Gauntlet game {game_code}') - post_lineups(all_lineups) - - await interaction.channel.send( - content=f'Game {gauntlets.games_played(this_run) + 1} of the run is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - - @group_new_game.command(name='exhibition', description='Start a new custom game against an AI') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def new_game_exhibition_command( - self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str, sp_card_id: int, - num_innings: Literal[9, 3] = 9, - cardsets: Literal['Minor League', 'Major League', 'Hall of Fame', 'Flashback', 'Custom'] = 'Custom'): - await interaction.response.defer() - - conflict = get_one_game(channel_id=interaction.channel.id, active=True) - if conflict: - await interaction.edit_original_response( - content=f'Ope. There is already a game going on in this channel. Please wait for it to complete ' - f'before starting a new one.') - return - - try: - if interaction.channel.category.name != 'Public Fields': - await interaction.response.send_message( - f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything ' - f'pops up?' - ) - return - except Exception as e: - logger.error(f'Could not check channel category: {e}') - - away_team = await get_team_by_abbrev(away_team_abbrev) - home_team = await get_team_by_abbrev(home_team_abbrev) - - if not away_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.' - ) - return - if not home_team: - await interaction.edit_original_response( - content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.' - ) - return - - for x in [away_team, home_team]: - if not x['is_ai']: - conflict = count_team_games(x['id']) - if conflict['count']: - await interaction.edit_original_response( - content=f'Ope. The {x["sname"]} are already playing over in ' - f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}' - ) - return - - current = await db_get('current') - week_num = current['week'] - # logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: {is_ranked}') - logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num}') - - if not away_team['is_ai'] and not home_team['is_ai']: - logger.error(f'Exhibition game between {away_team["abbrev"]} and {home_team["abbrev"]} has no AI') - await interaction.edit_original_response( - content=f'I don\'t see an AI team in this Exhibition game. Run `/new-game mlb-campaign` again with ' - f'an AI for a campaign game or `/new-game ` for a human game.' - ) - return - - ai_team = away_team if away_team['is_ai'] else home_team - human_team = away_team if home_team['is_ai'] else home_team - - if interaction.user.id not in [away_team['gmid'], home_team['gmid']]: - await interaction.edit_original_response( - content='You can only start a new game if you GM one of the teams.' - ) - return - - league_name = 'exhibition' - - this_game = post_game({ - 'away_team_id': away_team['id'], - 'home_team_id': home_team['id'], - 'week_num': week_num, - 'channel_id': interaction.channel.id, - 'active': True, - 'is_pd': True, - 'ranked': False, - 'season': current['season'], - 'short_game': True if num_innings == 3 else False, - 'game_type': league_name - }) - logger.info( - f'Game {this_game.id} ({league_name}) between {away_team_abbrev.upper()} and ' - f'{home_team_abbrev.upper()} is posted!' - ) - away_role = await team_role(interaction, away_team) - home_role = await team_role(interaction, home_team) - all_lineups = [] # Get Human SP - - human_sp_card = await db_get(f'cards', object_id=sp_card_id) - - if human_sp_card['team']['id'] != human_team['id']: - logger.error( - f'Card_id {sp_card_id} does not belong to {human_team["abbrev"]} in Game {this_game.id}' - ) - patch_game(this_game.id, active=False) - await interaction.channel.send( - f'Uh oh. Card ID {sp_card_id} is {human_sp_card["player"]["p_name"]} and belongs to ' - f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?') - return - - all_lineups.append({ - 'game_id': this_game.id, - 'team_id': human_team['id'], - 'player_id': human_sp_card['player']['player_id'], - 'card_id': sp_card_id, - 'position': 'P', - 'batting_order': 10, - 'after_play': 0 - }) - - async def get_ai_sp_roster(interaction, this_game, ai_team, home_team, league_name, all_lineups): - # Get AI Starting Pitcher - try: - await interaction.channel.send( - content=f'Now to decide on a Starting Pitcher...' - ) - if ai_team['id'] == this_game.away_team_id: - patch_game(this_game.id, away_roster_num=69, ai_team='away') - else: - patch_game(this_game.id, home_roster_num=69, ai_team='home') - - starter = await ai_manager.get_starting_pitcher( - ai_team, - this_game.id, - True if home_team['is_ai'] else False, - league_name - ) - all_lineups.append(starter) - ai_sp = await db_get('players', object_id=starter['player_id']) - - this_card = await db_get(f'cards', object_id=starter['card_id']) - await interaction.channel.send( - content=f'The {ai_team["sname"]} are starting **{player_desc(this_card["player"])}**:\n\n' - f'{player_pcard(this_card["player"])}' - ) - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start an AI game with {ai_team["sname"]}: {e}') - await interaction.channel.send( - content=f'Looks like the {ai_team["sname"]} rotation didn\'t come through clearly. I\'ll sort ' - f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - raise KeyError(f'A Starting Pitcher could not be found for the {ai_team["lname"]}.') - - # Get AI Lineup - try: - await interaction.channel.send( - content=f'I am getting a lineup card from the {ai_team["sname"]}...' - ) - - logger.info(f'new-game - calling lineup for {ai_team["abbrev"]}') - batters = await ai_manager.build_lineup( - ai_team, this_game.id, league_name, sp_name=ai_sp['p_name'] - ) - all_lineups.extend(batters) - logger.info(f'new-game - got lineup for {ai_team["abbrev"]}') - - except Exception as e: - patch_game(this_game.id, active=False) - logger.error(f'could not start an AI game with {ai_team["sname"]}: {e}') - await interaction.edit_original_response( - content=f'Looks like the {ai_team["sname"]} lineup card didn\'t come through clearly. I\'ll sort ' - f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end ' - f'this game - why don\'t you play against somebody else for now?' - ) - return - - logger.debug(f'Setting lineup for {ai_team["sname"]} in PD game') - logger.debug(f'lineups: {all_lineups}') - post_lineups(all_lineups) - - if cardsets in ['Minor League', 'Major League', 'Hall of Fame', 'Flashback']: - if cardsets == 'Minor League': - cardset_ids = '17,8' - backup_cardset_ids = '13' - elif cardsets == 'Major League': - cardset_ids = '17,18,13,11,7,8' - backup_cardset_ids = '9,3' - elif cardsets == 'Hall of Fame': - all_c = [str(x) for x in range(1, 20)] - cardset_ids = f'{",".join(all_c)}' - backup_cardset_ids = None - else: - # Flashback cardsets - cardset_ids = '11,7,6,12' - backup_cardset_ids = '13,5' - this_game = patch_game(this_game.id, cardset_ids=cardset_ids, backup_cardset_ids=backup_cardset_ids) - - await get_ai_sp_roster(interaction, this_game, ai_team, home_team, league_name, all_lineups) - - await interaction.channel.send( - content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - else: - async def my_callback(interaction: discord.Interaction, values): - cardset_ids = ','.join(values) - patch_game(this_game.id, cardset_ids=cardset_ids) - # await interaction.response.send_message( - # f'Your selection{"s are" if len(values) > 1 else " is"}: {", ".join(values)}') - - await get_ai_sp_roster(interaction, this_game, ai_team, home_team, league_name, all_lineups) - - await interaction.channel.send( - content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' - f'Go ahead and set lineups with the `/read-lineup` command!', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - my_dropdown = Dropdown( - option_list=SELECT_CARDSET_OPTIONS, - placeholder='Select up to 8 cardsets to include', - callback=my_callback, - max_values=len(SELECT_CARDSET_OPTIONS) - ) - view = DropdownView([my_dropdown]) - await interaction.edit_original_response( - content=None, - view=view - ) - - return - - @commands.command(name='force-endgame', help='Mod: Force a game to end without stats') - @commands.is_owner() - async def force_end_game_command(self, ctx: commands.Context): - this_game = get_one_game(channel_id=ctx.channel.id, active=True) - - try: - await ctx.send(content=None, embed=await self.initialize_play_plus_embed(this_game)) - except Exception as e: - logger.error(f'could not post game state embed: {e}') - question = await ctx.send( - f'Something is very borked here and I can\'t post the embed. Imma nuke this game now...' - ) - patch_game(this_game.id, active=False) - await question.edit(content='Done and dusted.', view=None) - return - - view = Confirm(responders=[ctx.author], timeout=60, label_type='yes') - question = await ctx.send(f'Should I nuke this game?', view=view) - await view.wait() - - if view.value: - patch_game(this_game.id, active=False) - await question.edit(content='It\'s gone.', view=None) - else: - await question.edit(content='It stays.', view=None) - - @commands.command(name='check-decisions', help='Mod: Calculate pitching decisions of current game') - @commands.is_owner() - async def check_decisions_command(self, ctx: commands.Context): - this_game = get_one_game(channel_id=ctx.channel.id, active=True) - get_pitching_decisions(this_game, this_game.id) - await ctx.send(random_conf_gif()) - - @app_commands.command(name='end-game', description='End game in this channel') - @app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME) - async def end_game_command(self, interaction: discord.Interaction): - await interaction.response.defer() - - this_game = get_one_game(channel_id=interaction.channel.id, active=True) - if not this_game: - await interaction.edit_original_response(content='Ope, I don\'t see a game in this channel.') - return - logger.info(f'Ending Game {this_game.id}') - - response = await interaction.edit_original_response(content=f'Let\'s see what we\'ve got here...') - - owner_team = await get_game_team(this_game, interaction.user.id) - gauntlet_team = None - if 'gauntlet' in this_game.game_type: - gauntlet_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}') - - if not {owner_team['id'], gauntlet_team['id']}.intersection( - [this_game.away_team_id, this_game.home_team_id]): - await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can end games.') - return - elif not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id] and \ - interaction.user.id != self.bot.owner_id: - await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can end games.') - return - - latest_play = get_latest_play(this_game.id) - - if latest_play is None: - 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 off 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 - - valid_end = False - logger.debug(f'latest play: {latest_play}') - if not this_game.short_game: - if latest_play.starting_outs == 0: - logger.debug(f'no outs') - if latest_play.inning_half.lower() == 'top': - logger.debug(f'top of inning') - if latest_play.inning_num > 9 and latest_play.away_score != latest_play.home_score: - logger.debug(f'after the ninth and not tied') - valid_end = True - if abs(latest_play.home_score - latest_play.away_score) >= 10: - logger.debug(f'not after ninth, but mercy') - valid_end = True - if latest_play.inning_half.lower() == 'bot': - if (latest_play.home_score > latest_play.away_score) and latest_play.inning_num >= 9: - logger.debug(f'bottom half and home team winning') - valid_end = True - if abs(latest_play.home_score - latest_play.away_score) >= 10: - logger.debug(f'bottom half and mercy') - valid_end = True - elif abs(latest_play.home_score - latest_play.away_score) >= 10 and latest_play.inning_half.lower() == 'bot': - logger.info(f'bottom half and it is a mercy') - valid_end = True - elif latest_play.inning_num >= 9 and latest_play.inning_half.lower() == 'bot' and \ - latest_play.home_score > latest_play.away_score: - valid_end = True - else: - if latest_play.starting_outs == 0: - logger.debug(f'no outs') - if latest_play.inning_half.lower() == 'top': - logger.debug(f'top of inning') - if latest_play.inning_num > 3 and latest_play.away_score != latest_play.home_score: - logger.debug(f'after the ninth and not tied') - valid_end = True - if abs(latest_play.home_score - latest_play.away_score) >= 10: - logger.debug(f'not after ninth, but mercy') - valid_end = True - if latest_play.inning_half.lower() == 'bot': - if (latest_play.home_score > latest_play.away_score) and latest_play.inning_num >= 3: - logger.debug(f'bottom half and home team winning') - valid_end = True - if abs(latest_play.home_score - latest_play.away_score) >= 10: - logger.debug(f'bottom half and mercy') - valid_end = True - elif abs(latest_play.home_score - latest_play.away_score) >= 10 and latest_play.inning_half.lower() == 'bot': - logger.info(f'bottom half and it is a mercy') - valid_end = True - elif latest_play.inning_num >= 3 and latest_play.inning_half.lower() == 'bot' and \ - latest_play.home_score > latest_play.away_score: - 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 and ' - 'you will take the L.\n\n' - 'Should I end this game?', - view=view - ) - await view.wait() - - if view.value: - await question.delete()# New database driven stat submission - failure = False - final_game = await self.post_stratgame(this_game) - - # Send Plays to db - try: - resp = await self.post_allplays(this_game, final_game['id']) - if not resp: - failure = True - except Exception as e: - logger.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: - logger.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: - logger.error(f'could not delete decisions') - - try: - await db_delete(f'plays/game', object_id=final_game["id"]) - except Exception as e: - logger.error(f'could not delete plays') - - try: - await db_delete(f'games', object_id=final_game["id"]) - except Exception as e: - logger.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 - - 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 - - else: - await question.edit( - content='It stays.', view=None - ) - return - - await response.edit(content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False)) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.edit_original_response(content=f'Should I end this game?', view=view) - await view.wait() - - if view.value: - await question.edit(content='I\'ll tally the scorecard now...', view=None) - else: - await question.edit(content='It stays.', view=None) - return - - # New database driven stat submission - failure = False - final_game = await self.post_stratgame(this_game) - - # Send Plays to db - try: - resp = await self.post_allplays(this_game, final_game['id']) - if not resp: - failure = True - except Exception as e: - logger.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: - logger.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: - logger.error(f'could not delete decisions') - - try: - await db_delete(f'plays/game', object_id=final_game["id"]) - except Exception as e: - logger.error(f'could not delete plays') - - try: - await db_delete(f'games', object_id=final_game["id"]) - except Exception as e: - logger.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 - - gs = await db_get(f'plays/game-summary/{final_game["id"]}') - await db_patch('games', object_id=gs['game']['id'], - params=[('away_score', gs['runs']['away']), ('home_score', gs['runs']['home'])]) - - away_team = gs['teams']['away'] - home_team = gs['teams']['home'] - 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'] - - # Post a notification to PD - logger.debug(f'getting inning') - 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"]} {latest_play.away_score} @ {latest_play.home_score} {home_team["lname"]} - F/' - f'{inning}', - winning_team - ) - - logger.debug(f'setting location') - embed.add_field( - name='Location', - value=f'{interaction.guild.get_channel(this_game.channel_id).mention}' - ) - - embed.add_field(name='Game ID', value=f'{final_game["id"]}') - - logger.debug(f'getting league name') - 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.game_type == 'flashback': - game_des = 'Flashback' - 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"}' - logger.debug(f'building box score') - embed.add_field( - name='Box Score', - value=f'```\n' - f'Team | R | H | E |\n' - f'{away_team["abbrev"].replace("Gauntlet-", ""): <4} | {gs["runs"]["away"]: >2} | ' - f'{gs["hits"]["away"]: >2} | {gs["errors"]["away"]: >2} |\n' - f'{home_team["abbrev"].replace("Gauntlet-", ""): <4} | {gs["runs"]["home"]: >2} | ' - f'{gs["hits"]["home"]: >2} | {gs["errors"]["home"]: >2} |\n' - f'\n```', - inline=False - ) - - logger.debug(f'getting potg string') - tp = gs["top-players"][0] - potg_string = f'{player_desc(tp["player"])} - ' - if 'hr' in tp: - potg_string += f'{tp["hit"]}-{tp["ab"]}' - if tp['hr'] > 0: - num = f'{tp["hr"]} ' if tp["hr"] > 1 else "" - potg_string += f', {num}HR' - if tp['triple'] > 0: - num = f'{tp["triple"]} ' if tp["triple"] > 1 else "" - potg_string += f', {num}3B' - if tp['double'] > 0: - num = f'{tp["double"]} ' if tp["double"] > 1 else "" - potg_string += f', {num}2B' - if tp['run'] > 0: - potg_string += f', {tp["run"]} R' - if tp['rbi'] > 0: - potg_string += f', {tp["rbi"]} RBI' - else: - potg_string = f'{player_desc(tp["player"])} - {tp["ip"]} IP, {tp["run"]} R' - if tp['run'] != tp['e_run']: - potg_string += f' ({tp["e_run"]} ER)' - potg_string += f', {tp["hit"]} H, {tp["so"]} K' - potg_string += f', {tp["re24"]:.2f} re24' - embed.add_field( - name='Player of the Game', - value=potg_string, - inline=False - ) - - logger.info(f'potg: {potg_string}') - logger.debug(f'getting pitcher string') - pit_string = f'Win: {gs["pitchers"]["win"]["p_name"]}\n' \ - f'Loss: {gs["pitchers"]["loss"]["p_name"]}\n' - if gs['pitchers']['save'] is not None: - pit_string += f'Save: {player_desc(gs["pitchers"]["save"])}' - embed.add_field( - name=f'Pitching', - value=pit_string, - ) - - def name_list(raw_list: list) -> str: - logger.info(f'raw_list: {raw_list}') - player_dict = {} - for x in raw_list: - if x['player_id'] not in player_dict: - player_dict[x['player_id']] = x - - data_dict = {} - for x in raw_list: - if x['player_id'] not in data_dict: - data_dict[x['player_id']] = 1 - else: - data_dict[x['player_id']] += 1 - - r_string = '' - logger.info(f'players: {player_dict} / data: {data_dict}') - - first = True - for p_id in data_dict: - r_string += f'{", " if not first else ""}{player_dict[p_id]["p_name"]}' - if data_dict[p_id] > 1: - r_string += f' {data_dict[p_id]}' - first = False - - return r_string - - logger.info(f'getting running string') - if len(gs['running']['sb']) + len(gs['running']['csc']) > 0: - run_string = '' - if len(gs['running']['sb']) > 0: - run_string += f'SB: {name_list(gs["running"]["sb"])}\n' - - if len(gs['running']['csc']) > 0: - run_string += f'CSc: {name_list(gs["running"]["csc"])}' - - embed.add_field( - name=f'Baserunning', - value=run_string - ) - - logger.info(f'getting xbh string') - if len(gs['xbh']['2b']) + len(gs['xbh']['3b']) + len(gs['xbh']['hr']) > 0: - bat_string = '' - if len(gs['xbh']['2b']) > 0: - bat_string += f'2B: {name_list(gs["xbh"]["2b"])}\n' - - if len(gs['xbh']['3b']) > 0: - bat_string += f'3B: {name_list(gs["xbh"]["3b"])}\n' - - if len(gs['xbh']['hr']) > 0: - bat_string += f'HR: {name_list(gs["xbh"]["hr"])}\n' - else: - bat_string = 'Oops! All bitches! No XBH from either team.' - - logger.info(f'building embed') - embed.add_field( - name='Batting', - value=bat_string, - 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 - ) - logger.info(f'sending scorebug') - 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, - responders=[interaction.user] - ) - - 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) - - logger.info(f'Game {this_game.id} is complete') - if gauntlet_team is None: - 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'] - # } - # - # logger.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: - # # logger.info(f'line: {line}') - # this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) - # # logger.info(f'away / this_stats: {this_stats}') - # away_stats['p_lines'].extend(this_stats) - # if 'score' not in home_stats: - # # logger.info(f'score not in home_stats') - # home_stats['score'] = this_stats[0]['pl_runs'] - # else: - # # logger.info(f'score is in home_stats') - # home_stats['score'] += this_stats[0]['pl_runs'] - # if 'hits' not in home_stats: - # # logger.info(f'hits not in home_stats') - # home_stats['hits'] = this_stats[0]['pl_hit'] - # else: - # # logger.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) - # logger.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: - # # logger.info(f'line: {line}') - # this_stats = get_pitching_stats(this_game.id, lineup_id=line.id) - # # logger.info(f'home / this_stats: {this_stats}') - # home_stats['p_lines'].extend(this_stats) - # if 'score' not in away_stats: - # # logger.info(f'score not in away_stats') - # away_stats['score'] = this_stats[0]['pl_runs'] - # else: - # # logger.info(f'score is in away_stats') - # away_stats['score'] += this_stats[0]['pl_runs'] - # if 'hits' not in away_stats: - # # logger.info(f'hits not in away_stats') - # away_stats['hits'] = this_stats[0]['pl_hit'] - # else: - # # logger.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) - # logger.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!' - # ) - # - # logger.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: - # logger.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 - # logger.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 - # - # logger.debug(f'away_stats (in /endgame function)\n\n{away_stats}') - # logger.debug(f'home_stats (in /endgame function)\n\n{home_stats}') - # logger.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}') - # - # logger.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) - # - # logger.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' - ) - @app_commands.describe( - roster='Which roster to pull from your sheet?', - lineup='Which handedness lineup are you using?' - ) - @app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME) - async def read_lineup_command( - self, interaction: discord.Interaction, roster: Literal['Primary', 'Secondary', 'Ranked'], - lineup: Literal['v Right', 'v Left']): - this_game = get_one_game(channel_id=interaction.channel_id, active=True) - if not this_game: - await interaction.response.send_message(f'I dont\'t see an active game in this channel!') - return - - if not this_game.is_pd: - await interaction.response.send_message(f'Lineup imports are only supported for PD games right now.' - f'Please use the `/setlineup` command.') - return - - lineup_team = await get_game_team(this_game, interaction.user.id) - logger.debug(f'read_lineup_command - lineup_team: {lineup_team}') - if 'gauntlet' in this_game.game_type: - lineup_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{lineup_team["abbrev"]}') - if not lineup_team['id'] in [this_game.away_team_id, this_game.home_team_id]: - logger.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} when they ' - f'aren\'t a GM in the game.') - await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can pull lineups.') - return - - existing_lineups = await get_team_lineups(this_game.id, lineup_team['id'], as_string=False) - logger.debug(f'read_lineup_command - existing_lineups:\n{existing_lineups}') - if len(existing_lineups) > 1: - await interaction.response.send_message( - f'It looks like the {lineup_team["sname"]} already have a lineup. Run `/substitution` to make changes.' - ) - return - - await interaction.response.send_message(f'Let\'s put this lineup card together...') - - if lineup == 'v Right': - l_num = 1 - else: - l_num = 2 - - if roster == 'Primary': - roster_num = 1 - elif roster == 'Secondary': - roster_num = 2 - else: - roster_num = 3 - lineup_cells = get_roster_lineups(lineup_team, self.bot, roster_num, l_num) - - all_lineups = [] - all_pos = [] - card_ids = [] - for index, row in enumerate(lineup_cells): - if '' in row: - break - - if row[0].upper() not in all_pos: - all_pos.append(row[0].upper()) - else: - raise SyntaxError(f'You have more than one {row[0].upper()} in this lineup. Please ' - f'update and set the lineup again.') - - this_card = await db_get(f'cards', object_id=int(row[1])) - if this_card is None: - raise LookupError( - f'Your {row[0].upper()} has a Card ID or {int(row[1])} and I cannot find that card. Did you sell ' - f'that card by chance? Or did you sell a duplicate and the bot sold the one you were using?' - ) - if this_card['team']['id'] != lineup_team['id']: - raise SyntaxError(f'Easy there, champ. Looks like card ID {row[1]} belongs to the ' - f'{this_card["team"]["sname"]}. Try again with only cards you own.') - player_id = this_card['player']['player_id'] - card_id = row[1] - card_ids.append(str(card_id)) - - this_lineup = { - 'game_id': this_game.id, - 'team_id': lineup_team['id'], - 'player_id': player_id, - 'card_id': card_id, - 'position': row[0].upper(), - 'batting_order': index + 1, - 'after_play': 0 - } - - all_lineups.append(this_lineup) - - if lineup_team['id'] == this_game.away_team_id: - patch_game(this_game.id, away_roster_num=roster_num) - else: - patch_game(this_game.id, home_roster_num=roster_num) - - # Check roster legality - if this_game.game_type in ['major-league', 'hall-of-fame']: - l_check = await legal_check(card_ids, 'ranked') - if not l_check['legal']: - await interaction.edit_original_response( - content=f'It looks like this is a Ranked Legal game and I see the following cards as illegal. ' - f'Please adjust your lineup and re-submit!\n\n' - f'- {l_check["error_string"]}' - ) - return - - if this_game.game_type == 'flashback': - l_check = await legal_check(card_ids, 'flashback') - if not l_check['legal']: - patch_game(this_game.id, active=False) - await interaction.edit_original_response( - content=f'It looks like this is a Flashback game and I see the following cards as illegal. ' - f'Please adjust your lineup and re-submit!\n\n' - f'- {l_check["error_string"]}' - ) - return - - logger.debug(f'Setting lineup for {lineup_team["sname"]} in PD game') - post_lineups(all_lineups) - - try: - await interaction.channel.send(content=None, embed=await self.initialize_play_plus_embed(this_game)) - except IntegrityError as e: - logger.debug(f'Unable to pull game_state for game_id {this_game.id} until both lineups are in: {e}') - await interaction.response.send_message(f'Game state will be posted once both lineups are in') - return - - @commands.command(name='get-bullpen', help='Mod: Sync an AI bullpen') - @commands.is_owner() - async def get_bullpen_command(self, ctx: commands.Context, team_id): - team = await db_get('teams', object_id=team_id) - if not team: - await ctx.send(f'I did not find a team with id {team_id}') - return - - await ctx.send(f'I\'m getting bullpen data from {team["gmname"]}...') - get_or_create_bullpen(team, self.bot) - - await ctx.send(f'Got it!') - - group_substitution = app_commands.Group(name='substitute', description='Make a substitution in active game') - - @group_substitution.command(name='batter', description='Make a batter substitution') - @app_commands.describe( - batting_order='Batting order of new player', - new_player='Enter the Card ID (a number)') - @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME) - async def sub_batter_command( - self, interaction: discord.Interaction, new_player: int, batting_order: Literal[ - 'this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - new_pos: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'PH', 'PR']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - this_card = await db_get(f'cards', object_id=int(new_player)) - if this_card["team"]["id"] != owner_team['id']: - raise SyntaxError(f'Easy there, champ. Looks like card ID {new_player} belongs to the ' - f'{this_card["team"]["sname"]}. Try again with only cards you own.') - player_id = this_card['player']['player_id'] - card_id = new_player - - if this_game.game_type in ['major-league', 'hall-of-fame', 'tens']: - legality = await db_post(f'cards/legal-check/{this_game.game_type}?card_id={new_player}') - if legality['count'] > 0: - il_string = "\n- ".join(legality['bad_cards']) - await interaction.edit_original_response( - content=f'It looks like this is a {this_game.game_type.replace("-", " ").title()} game and I see ' - f'the following cards as illegal. Please take another look and re-submit!\n\n' - f'- {il_string}' - ) - return - - batting_order = int(batting_order) if batting_order != 'this-spot' else this_play.batting_order - - # Check for simple position change - in_lineup = get_one_lineup(this_game.id, team_id=owner_team['id'], active=True, batting_order=batting_order) - if in_lineup.card_id == int(card_id): - post_pos = patch_lineup(in_lineup.id, position=new_pos) - else: - this_lineup = { - 'game_id': this_game.id, - 'team_id': owner_team['id'], - 'player_id': player_id, - 'card_id': card_id, - 'position': new_pos.upper(), - 'batting_order': batting_order, - 'after_play': this_play.play_num - 1 if this_play else 0 - } - - make_sub(this_lineup) - - await interaction.edit_original_response( - content=None, - embed=await self.initialize_play_plus_embed(this_game) - ) - - @group_substitution.command(name='pitcher', description='Make a pitching change') - @app_commands.describe( - new_player='Enter the Card ID (a number)', - batting_order='Only enter this if you are forfeiting the DH') - @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - async def sub_pitcher_command( - self, interaction: discord.Interaction, new_player: int, - batting_order: Literal['this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9'] = None): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - this_card = await db_get(f'cards', object_id=int(new_player)) - if this_card["team"]["id"] != owner_team['id']: - raise SyntaxError(f'Easy there, champ. Looks like card ID {new_player} belongs to the ' - f'{this_card["team"]["sname"]}. Try again with only cards you own.') - player_id = this_card['player']['player_id'] - card_id = new_player - new_post = False - - # Check for simple position change - in_lineup = get_one_lineup(this_game.id, team_id=owner_team['id'], active=True, card_id=card_id) - if in_lineup is not None: - new_pitcher = patch_lineup(in_lineup.id, position='P') - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - q_text = f'It looks like you are forfeiting the DH by moving {player_desc(this_card["player"])} to ' \ - f'the mound. __You will not be able to undo this sub even with the undo-play command__ so real ' \ - f'quick: are you sure?' - question = await interaction.channel.send(q_text, view=view) - await view.wait() - - if view.value: - await question.edit(content=f'~~{q_text}~~\nFuck the DH \U0000270A', view=None) - else: - await question.delete() - await interaction.edit_original_response(content=f'~~{q_text}~~\nI will hold off for now.') - await interaction.channel.send( - content=None, - embed=await self.initialize_play_plus_embed(this_game) - ) - return - - old_pitcher = get_pitcher(this_game, this_play) - patch_lineup(old_pitcher.id, active=False) - patch_play(this_play.id, pitcher_id=new_pitcher.id) - this_play.pitcher = new_pitcher - else: - if this_play is None: - after_play = 0 - - old_pit_order = 10 - if batting_order is None: - batting_order = 10 - else: - batting_order = int(batting_order) - - else: - if this_play.pitcher.team_id != owner_team['id']: - await interaction.edit_original_response( - content='It looks like your team is batting right now - ' - 'please make this sub once you take the field.') - return - - old_pit_order = this_play.pitcher.batting_order - if batting_order is None: - batting_order = old_pit_order - else: - batting_order = int(batting_order) - - after_play = this_play.play_num - 1 - - this_lineup = { - 'game_id': this_game.id, - 'team_id': owner_team['id'], - 'player_id': player_id, - 'card_id': card_id, - 'position': 'P', - 'batting_order': batting_order, - 'after_play': after_play - } - - make_sub(this_lineup) - if old_pit_order != batting_order: - patch_lineup(this_play.pitcher.id, active=False) - - if new_post: - await interaction.channel.send( - content=None, - embed=await self.initialize_play_plus_embed(this_game) - ) - else: - await interaction.edit_original_response( - content=None, - embed=await self.initialize_play_plus_embed(this_game) - ) - - # @group_substitution.command(name='forfeit-dh', description='Have the pitcher bat in the DH spot') - # @commands.has_any_role(PD_PLAYERS_ROLE_NAME) - # async def sub_forfeitdh_command(self, interaction: discord.Interaction): - # this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - # if False in (this_game, owner_team, this_play): - # return - # - - @commands.hybrid_command(name='gamestate', help='Post the current game state', aliases=['gs']) - @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME) - async def game_state_command(self, ctx: commands.Context, include_lineups: bool = True): - this_game = get_one_game(channel_id=ctx.channel.id, active=True) - if not this_game: - await ctx.send(f'I dont\'t see an active game in this channel!') - return - - response = await ctx.send(f'Building the scorebug now...') - - await response.edit(content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=include_lineups)) - - async def checks_log_interaction(self, interaction: discord.Interaction, block_rollback: Optional[bool] = False) \ - -> tuple[Optional[StratGame], Optional[dict], Optional[StratPlay]]: - await interaction.response.defer() - - this_game = get_one_game(channel_id=interaction.channel.id, active=True) - if not this_game: - await interaction.edit_original_response(content='I don\'t see a game in this channel.') - return False, False, False - - owner_team = await get_game_team(this_game, interaction.user.id) - if 'gauntlet' in this_game.game_type: - owner_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}') - if not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id]: - logger.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} when they ' - f'aren\'t a GM in the game.') - await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can log plays.') - # return this_game, False, False - - this_play = get_current_play(this_game.id) - if this_play is not None: - # Allow specific commands to not rollback the play (e.g. /show-card) - if this_play.locked and not block_rollback: - logger.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} while the ' - f'play was locked.') - undo_play(this_play.id) - await interaction.edit_original_response( - content=f'Looks like your game got hung up there for a second. I just rolled it back a play to ' - f'release it. If you have any more issues, let Cal know.' - ) - this_play = get_current_play(this_game.id) - - if not this_play.pitcher: - logger.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} without a ' - f'pitcher in the lineup.') - await interaction.edit_original_response(content=f'Please sub in a pitcher before logging a new play.') - this_play = None - - return this_game, owner_team, this_play - - group_log = app_commands.Group(name='log', description='Log a play in this channel\'s game') - - @group_log.command(name='ai-pitcher-sub', description='Run automated substitution when the AI wants a change') - async def ai_pitcher_sub(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - away_team = await get_game_team(this_game, team_id=this_game.away_team_id) - home_team = await get_game_team(this_game, team_id=this_game.home_team_id) - ai_team = away_team if owner_team['id'] == home_team['id'] else home_team - - if this_play.batter.team_id == ai_team['id']: - await interaction.edit_original_response( - content=f'It looks like the {ai_team["sname"]} are batting now. If they need a sub, please do so when ' - f'they are back on defense.' - ) - return - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers cook in some ' - f'cases. Are you sure you want to manually run a sub for them?', - view=view - ) - await view.wait() - - if view.value: - await question.edit( - content=f'~~Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers ' - f'cook in some cases. Are you sure you want to manually run a sub for them?~~\n\nI let Cal ' - f'know his stupid AI isn\'t working.', - view=None - ) - await send_to_channel( - self.bot, - 'commissioners-office', - content=f'{interaction.user.display_name} just ran a manual sub here: {question.jump_url}') - else: - await question.delete() - await interaction.edit_original_response( - content='Jkjkjk, we will let the ai decide when to make subs.', - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - - curr_pitcher = get_one_lineup(this_game.id, team_id=ai_team['id'], position='P') - pit_plays = get_plays(this_game.id, curr_pitcher.id) - logger.debug(f'pit_plays for sub in Game {this_game.id}: {pit_plays}') - if pit_plays['count'] < 2: - pitcher = await get_player(this_game, curr_pitcher) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'It doesn\'t look like {pitcher["p_name"]} is fatigued - are you sure they should be subbed out?', - view=view - ) - await view.wait() - - if view.value: - await question.delete() - await interaction.channel.send( - content=f'Thanks! I let {get_cal_user(interaction).mention} know there was an issue with ' - f'{ai_team["abbrev"]} pitchers.' - ) - else: - await question.delete() - await interaction.edit_original_response(content=f'Okay, I\'ll leave them in!') - return - - # new_pitcher = await next_pitcher(this_play, ai_team, self.bot) - # logger.debug(f'new_pitcher: {new_pitcher}') - # - # this_lineup = { - # 'game_id': this_game.id, - # 'team_id': ai_team['id'], - # 'player_id': new_pitcher['player']['player_id'], - # 'card_id': new_pitcher['card_id'], - # 'position': 'P', - # 'batting_order': 10, - # 'after_play': this_play.play_num - 1 - # } - # make_sub(this_lineup) - - used_pitchers = await get_team_lineups( - game_id=this_play.game.id, team_id=ai_team['id'], inc_inactive=True, as_string=False - ) - make_sub(await ai_manager.get_relief_pitcher(this_play, ai_team, this_game.game_type)) - await interaction.edit_original_response( - content=None, - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c') - async def log_flyball( - self, interaction: discord.Interaction, flyball_type: Literal['a', 'b', 'ballpark', 'b?', 'c']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - await self.flyballs(interaction, this_game, this_play, flyball_type) - - if flyball_type not in ['a', 'c'] and this_play.on_base_code > 0: - await interaction.edit_original_response(content=f'Flyball has been logged') - await interaction.channel.send( - content=None, - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - else: - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='groundball', description='Groundballs: a, b, c') - async def log_groundball(self, interaction: discord.Interaction, groundball_type: Literal['a', 'b', 'c']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - await self.groundballs(interaction, this_game, this_play, groundball_type) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='single', description='Singles: *, **, ballpark, uncapped') - async def log_single( - self, interaction: discord.Interaction, single_type: Literal['*', '**', 'ballpark', 'uncapped']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - if single_type == '**': - single_wellhit(this_play) - elif single_type == '*': - single_onestar(this_play) - elif single_type == 'ballpark': - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, num_bases=1) - patch_play(this_play.id, pa=1, ab=1, hit=1, bp1b=1) - complete_play(this_play.id, batter_to_base=1) - elif single_type == 'uncapped': - patch_play(this_play.id, locked=True, pa=1, ab=1, hit=1) - advance_runners(this_play.id, 1) - this_play = get_current_play(this_game.id) - batter_to_base = 1 - - if this_play.on_base_code in [1, 2, 4, 5, 6, 7]: - ai_manager = get_manager(this_game) - ai_is_batting = ai_batting(this_game, this_play) - def_team = await db_get('teams', object_id=this_play.pitcher.team_id) - to_bases = [None, None, 'to second', 'to third', 'home'] - at_bases = [None, None, 'at second', 'at third', 'at home'] - - if this_play.on_second: - lead_runner = await get_player(this_game, this_play.on_second) - lead_base = 4 - if this_play.on_first: - trail_runner = await get_player(this_game, this_play.on_first) - trail_base = 3 - else: - trail_runner = await get_player(this_game, this_play.batter) - trail_base = 2 - else: - lead_runner = await get_player(this_game, this_play.on_first) - lead_base = 3 - trail_runner = await get_player(this_game, this_play.batter) - trail_base = 2 - - ai_hint = '' - if this_game.ai_team and ai_is_batting: - ai_hint = f'*The runner will ' \ - f'{ai_manager.uncapped_advance(lead_base, this_play.starting_outs)}*' - - logger.debug(f'calling of embed') - await show_outfield_cards(interaction, this_play) - logger.debug(f'done with of embed') - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {lead_runner["p_name"]} being sent {to_bases[lead_base]}?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and not ai_is_batting: - ai_hint = f'*The defense will ' \ - f'{ai_manager.throw_lead_runner(lead_base, this_play.starting_outs)}*' - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is the defense throwing {to_bases[lead_base]}?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and ai_is_batting: - ai_hint = f'*The runner will ' \ - f'{ai_manager.trail_advance(trail_base, this_play.starting_outs, True if lead_base == 4 else False)}*' - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {trail_runner["p_name"]} being sent {to_bases[trail_base]}?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and not ai_is_batting: - ai_hint = f'*The defense will ' \ - f'{ai_manager.throw_which_runner(lead_base, this_play.starting_outs)}*' - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - view.confirm.label = 'Home Plate' if lead_base == 4 else 'Third Base' - view.cancel.label = 'Third Base' if trail_base == 3 else 'Second Base' - question = await interaction.channel.send( - f'Is the throw going {to_bases[lead_base]} or {to_bases[trail_base]}?\n\n{ai_hint}', - view=view - ) - await view.wait() - - # Throw to lead runner - if view.value: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {lead_runner["p_name"]} thrown out {at_bases[lead_base]}?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - advance_runners(this_play.id, 2) - batter_to_base = 2 - if lead_base == 4: - patch_play(this_play.id, on_second_final=False, outs=1) - else: - patch_play(this_play.id, on_first_final=False, outs=1) - - else: - await question.delete() - advance_runners(this_play.id, 2) - batter_to_base = 2 - - # Throw to trail runner - else: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {trail_runner["p_name"]} thrown out {at_bases[trail_base]}?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - advance_runners(this_play.id, 2) - if trail_base == 3: - patch_play(this_play.id, on_first_final=False, outs=1) - batter_to_base = 2 - else: - patch_play(this_play.id, outs=1) - batter_to_base = None - - else: - await question.delete() - advance_runners(this_play.id, 2) - batter_to_base = 2 - - else: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {lead_runner["p_name"]} thrown out {at_bases[lead_base]}?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if lead_base == 4: - patch_play(this_play.id, on_second_final=False, outs=1) - else: - patch_play(this_play.id, on_first_final=False, outs=1) - - else: - await question.delete() - advance_one_runner(this_play.id, from_base=lead_base - 2, num_bases=2) - - else: - await question.delete() - advance_one_runner(this_play.id, from_base=lead_base - 2, num_bases=2) - - else: - await question.delete() - - logger.debug(f'post process batter runner on_second_final: {this_play.on_second_final}') - complete_play(this_play.id, batter_to_base=batter_to_base) - - if single_type == 'uncapped': - await interaction.edit_original_response(content=f'Uncapped single has been logged') - await interaction.channel.send( - content=None, - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - else: - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='frame-pitch', description=f'Walk/strikeout split; determined by home plate umpire') - async def log_frame_check(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - frame_result = dice.frame_plate_check(owner_team, this_game.id) - logger.info(f'Frame Result:\n{frame_result}') - await interaction.edit_original_response( - content=None, - embed=frame_result['embed'] - ) - - if frame_result['is_walk']: - advance_runners(this_play.id, num_bases=1, only_forced=True) - patch_play(this_play.id, pa=1, walk=1) - batter_to_base = 1 - else: - patch_play(this_play.id, pa=1, ab=1, outs=1, so=1) - advance_runners(this_play.id, 0) - batter_to_base = None - - complete_play(this_play.id, batter_to_base=batter_to_base) - - await interaction.channel.send( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='double', description='Doubles: **, ***, uncapped') - async def log_double(self, interaction: discord.Interaction, double_type: Literal['**', '***', 'uncapped']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - if double_type == '**': - double_twostar(this_play) - elif double_type == '***': - double_threestar(this_play) - elif double_type == 'uncapped': - advance_runners(this_play.id, 2) - this_play = patch_play(this_play.id, locked=True, pa=1, ab=1, hit=1, double=1) - - batter_to_base = 2 - ai_is_batting = ai_batting(this_game, this_play) - this_manager = get_manager(this_game) - - if this_play.on_first: - ai_hint = '' - if this_game.ai_team and ai_is_batting: - if this_play.on_first: - ai_hint = f'*The runner will attempt to advance*' - else: - ai_hint = f'*The runner will ' \ - f'{this_manager.uncapped_advance(4, this_play.starting_outs)}*' - - logger.debug(f'calling of embed') - await show_outfield_cards(interaction, this_play) - logger.debug(f'done with of embed') - - runner_to_home = await get_player(this_game, this_play.on_first) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {runner_to_home["p_name"]} being sent home?\n\n{ai_hint}', view=view - ) - await view.wait() - - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and not ai_is_batting: - ai_hint = f'*The defense will {this_manager.throw_lead_runner(4, this_play.starting_outs)}*' - - # Throw for lead runner? - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is the defense throwing home?\n\n{ai_hint}', view=view - ) - await view.wait() - - # Yes: Send Trail runner? - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and ai_is_batting: - ai_hint = f'*The trail runner will ' \ - f'{this_manager.trail_advance(3, this_play.starting_outs, True)}*' - - batter_runner = await get_player(this_game, this_play.batter) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {batter_runner["p_name"]} being sent to third?\n\n{ai_hint}', view=view - ) - await view.wait() - - # Yes: Throw lead or trail? - if view.value: - await question.delete() - ai_hint = '' - if this_game.ai_team and not ai_is_batting: - ai_hint = f'*The defense will ' \ - f'{this_manager.throw_which_runner(4, this_play.starting_outs)}*' - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - view.confirm.label = 'Home Plate' - view.cancel.label = 'Third Base' - question = await interaction.channel.send( - f'Is the throw going to home plate or to third base?\n\n{ai_hint}', view=view - ) - await view.wait() - - # Throw home - if view.value: - batter_to_base = 3 - - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {runner_to_home["p_name"]} thrown out at the plate?', view=view - ) - await view.wait() - - # Out at the plate - if view.value: - await question.delete() - patch_play(this_play.id, on_first_final=False, outs=1) - - # Safe at the plate - else: - await question.delete() - advance_runners(this_play.id, 3) - - # Throw to third - else: - await question.delete() - advance_runners(this_play.id, num_bases=3) - - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {batter_runner["p_name"]} thrown out at third?', view=view - ) - await view.wait() - - # Out at third - if view.value: - await question.delete() - batter_to_base = None - advance_runners(this_play.id, num_bases=3) - patch_play(this_play.id, outs=1) - - # Safe at home and third - else: - batter_to_base = 3 - await question.delete() - - # No: Safe at home? - else: - await question.delete() - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - content=f'Was {runner_to_home["p_name"]} thrown out at the plate?', view=view - ) - await view.wait() - - # Out at the plate - if view.value: - await question.delete() - patch_play(this_play.id, on_first_final=False, outs=1) - - # Safe at the plate - else: - await question.delete() - advance_runners(this_play.id, num_bases=3) - - # No: End of play - else: - await question.delete() - advance_runners(this_play.id, num_bases=3) - else: - await question.delete() - - complete_play(this_play.id, batter_to_base=batter_to_base) - - if double_type == 'uncapped': - await interaction.edit_original_response(content=f'Uncapped double has been logged') - await interaction.channel.send( - content=None, - embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - else: - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='triple', description='Triples: no sub-types') - async def log_triple(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - triple(this_play) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='homerun', description='Home Runs: ballpark, no-doubt') - async def log_homerun(self, interaction: discord.Interaction, homerun_type: Literal['ballpark', 'no-doubt']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - advance_runners(this_play.id, num_bases=4) - if homerun_type == 'ballpark': - patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1, bphr=1) - elif homerun_type == 'no-doubt': - patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1) - complete_play(this_play.id, batter_to_base=4) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='walk', description='Walks: unintentional, intentional') - async def log_walk(self, interaction: discord.Interaction, walk_type: Literal['unintentional', 'intentional']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, num_bases=1, only_forced=True) - - if walk_type == 'unintentional': - patch_play(this_play.id, pa=1, walk=1) - elif walk_type == 'intentional': - patch_play(this_play.id, pa=1, ibb=1) - - complete_play(this_play.id, batter_to_base=1) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='chaos', description='Chaos: wild-pitch, passed-ball, balk, pickoff') - async def log_chaos(self, interaction: discord.Interaction, - chaos_type: Literal['wild-pitch', 'passed-ball', 'balk', 'pickoff']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, 0) - - if chaos_type == 'wild-pitch': - advance_runners(this_play.id, 1) - patch_play(this_play.id, rbi=0, wp=1) - elif chaos_type == 'passed-ball': - advance_runners(this_play.id, 1) - patch_play(this_play.id, rbi=0, pb=1) - elif chaos_type == 'balk': - advance_runners(this_play.id, 1) - patch_play(this_play.id, rbi=0, balk=1) - elif chaos_type == 'pickoff': - # Get from base - runner_flag = False - patch_play(this_play.id, pick=1) - - if this_play.on_base_code in [1, 2, 3]: - if this_play.on_first: - patch_play(this_play.id, on_first_final=False, runner_id=this_play.on_first.id, outs=1) - elif this_play.on_second: - patch_play(this_play.id, on_second_final=False, runner_id=this_play.on_second.id, outs=1) - elif this_play.on_third: - patch_play(this_play.id, on_third_final=False, runner_id=this_play.on_third.id, outs=1) - - else: - if this_play.on_first: - this_runner = await get_player(this_game, this_play.on_first) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send(f'Was {this_runner["p_name"]} picked off?', view=view) - await view.wait() - - if view.value: - patch_play(this_play.id, on_first_final=False, runner_id=this_play.on_first.id, outs=1) - runner_flag = True - - await question.delete() - - if this_play.on_second and not runner_flag: - this_runner = await get_player(this_game, this_play.on_second) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send(f'Was {this_runner["p_name"]} picked off?', view=view) - await view.wait() - - if view.value: - patch_play(this_play.id, on_second_final=False, runner_id=this_play.on_second.id, outs=1) - runner_flag = True - - await question.delete() - - if this_play.on_third and not runner_flag: - this_runner = await get_player(this_game, this_play.on_third) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send(f'Was {this_runner["p_name"]} picked off?', view=view) - await view.wait() - - if view.value: - patch_play(this_play.id, on_third_final=False, runner_id=this_play.on_third.id, outs=1) - runner_flag = True - - await question.delete() - - if not runner_flag: - await interaction.edit_original_response(content=f'So I guess nobody got picked off?') - patch_play(this_play.id, locked=False) - return - - complete_play(this_play.id) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='stealing', description='Running: stolen-base, caught-stealing') - @app_commands.describe(to_base='Base the runner is advancing to; 2 for 2nd, 3 for 3rd, 4 for Home') - async def log_stealing( - self, interaction: discord.Interaction, - running_type: Literal['stolen-base', 'caught-stealing', 'steal-plus-overthrow'], - to_base: Literal[2, 3, 4]): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - catcher = get_one_lineup( - this_game.id, team_id=this_play.pitcher.team_id, position='C' - ) - advance_runners(this_play.id, 0) - - if running_type == 'stolen-base': - if to_base == 4 and this_play.on_third: - patch_play( - this_play.id, sb=1, on_third_final=4, runner_id=this_play.on_third.id, catcher_id=catcher.id - ) - if this_play.on_second: - advance_one_runner(this_play.id, 2, 1) - if this_play.on_first: - advance_one_runner(this_play.id, 1, 1) - elif to_base == 3 and this_play.on_second: - if not this_play.on_third: - advance_runners(this_play.id, 1, is_error=True) - patch_play( - this_play.id, sb=1, on_second_final=3, runner_id=this_play.on_second.id, catcher_id=catcher.id - ) - else: - this_runner = await get_player(this_game, this_play.on_second) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at third.' - ) - patch_play(this_play.id, locked=False) - return - if this_play.on_first: - advance_one_runner( - this_play.id, from_base=1, num_bases=1 - ) - elif to_base == 2 and this_play.on_first: - if not this_play.on_second: - patch_play( - this_play.id, sb=1, on_first_final=2, runner_id=this_play.on_first.id, catcher_id=catcher.id - ) - else: - this_runner = await get_player(this_game, this_play.on_first) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at second.' - ) - patch_play(this_play.id, locked=False) - return - else: - await interaction.edit_original_response( - content=f'Uh oh - I don\'t see a runner there to steal the bag.' - ) - patch_play(this_play.id, locked=False) - return - - if running_type == 'steal-plus-overthrow': - if to_base == 4 and this_play.on_third: - patch_play( - this_play.id, sb=1, on_third_final=4, runner_id=this_play.on_third.id, catcher_id=catcher.id - ) - if this_play.on_second: - advance_one_runner(this_play.id, 2, 2) - if this_play.on_first: - advance_one_runner(this_play.id, 1, 2) - elif to_base == 3 and this_play.on_second: - advance_runners(this_play.id, 1) - if not this_play.on_third: - patch_play( - this_play.id, sb=1, on_second_final=4, runner_id=this_play.on_second.id, catcher_id=catcher.id - ) - else: - this_runner = await get_player(this_game, this_play.on_second) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at third.' - ) - patch_play(this_play.id, locked=False) - return - elif to_base == 2 and this_play.on_first: - if not this_play.on_second: - advance_runners(this_play.id, 1) - patch_play( - this_play.id, sb=1, on_first_final=3, runner_id=this_play.on_first.id, catcher_id=catcher.id - ) - else: - this_runner = await get_player(this_game, this_play.on_first) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at second.' - ) - patch_play(this_play.id, locked=False) - return - else: - await interaction.edit_original_response( - content=f'Uh oh - I don\'t see a runner there to steal the bag.' - ) - patch_play(this_play.id, locked=False) - return - - patch_play(this_play.id, error=1) - - elif running_type == 'caught-stealing': - if to_base == 4 and this_play.on_third: - patch_play( - this_play.id, cs=1, on_third_final=False, runner_id=this_play.on_third.id, - catcher_id=catcher.id, outs=1 - ) - if this_play.on_second: - advance_one_runner(this_play.id, 2, 1) - if this_play.on_first: - advance_one_runner(this_play.id, 1, 1) - elif to_base == 3 and this_play.on_second: - if not this_play.on_third: - advance_runners(this_play.id, 1) - patch_play( - this_play.id, cs=1, on_second_final=False, runner_id=this_play.on_second.id, - catcher_id=catcher.id, outs=1 - ) - else: - this_runner = await get_player(this_game, this_play.on_second) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at third.' - ) - patch_play(this_play.id, locked=False) - return - elif to_base == 2 and this_play.on_first: - if not this_play.on_second: - patch_play( - this_play.id, cs=1, on_first_final=False, runner_id=this_play.on_first.id, - catcher_id=catcher.id, outs=1 - ) - else: - this_runner = await get_player(this_game, this_play.on_first) - await interaction.edit_original_response( - content=f'Ope. Looks like {this_runner["p_name"]} is blocked by the runner at second.' - ) - patch_play(this_play.id, locked=False) - return - else: - await interaction.edit_original_response( - content=f'Uh oh - I don\'t see a runner there to steal the bag.' - ) - patch_play(this_play.id, locked=False) - return - - complete_play(this_play.id) - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='strikeout', description='Strikeout') - async def log_strikeout(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - patch_play(this_play.id, pa=1, ab=1, outs=1, so=1) - advance_runners(this_play.id, 0) - - complete_play(this_play.id) - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='popout', description='Popout') - async def log_popout(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - - patch_play(this_play.id, pa=1, ab=1, outs=1) - advance_runners(this_play.id, 0) - - complete_play(this_play.id) - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='lineout', description='Lineouts: one out, ballpark, max outs') - async def log_lineout( - self, interaction: discord.Interaction, lineout_type: Literal['one-out', 'ballpark', 'max-outs']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, 0) - - if lineout_type == 'one-out' or this_play.starting_outs == 2 or this_play.on_base_code == 0: - patch_play(this_play.id, pa=1, ab=1, outs=1) - - elif lineout_type == 'ballpark': - patch_play(this_play.id, pa=1, ab=1, outs=1, bplo=1) - - elif lineout_type == 'max-outs': - bases = ['third', 'second', 'first'] - num_outs = 1 - - for count, x in enumerate([this_play.on_third, this_play.on_second, this_play.on_first]): - if x: - runner = await get_player(this_game, x) - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Is {runner["p_name"]} out at {bases[count]} on the play?', view=view - ) - await view.wait() - - if view.value: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=False) - elif count == 1: - patch_play(this_play.id, on_second_final=False) - else: - patch_play(this_play.id, on_first_final=False) - num_outs += 1 - else: - await question.delete() - if count == 0: - patch_play(this_play.id, on_third_final=3) - elif count == 1: - patch_play(this_play.id, on_second_final=2) - else: - patch_play(this_play.id, on_first_final=1) - patch_play(this_play.id, pa=1, ab=1, outs=num_outs) - - complete_play(this_play.id) - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='hit-by-pitch', description='Batter to first; runners advance if forced') - async def log_hit_by_pitch_command(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=False) - - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, num_bases=1, only_forced=True) - patch_play(this_play.id, pa=1, hbp=1) - complete_play(this_play.id, batter_to_base=1) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='sac-bunt', description='Batter out; runners advance one base') - async def log_sac_bunt_command(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=False) - - patch_play(this_play.id, locked=True) - advance_runners(this_play.id, num_bases=1) - patch_play(this_play.id, pa=1, sac=1, outs=1) - complete_play(this_play.id) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='undo-play', description='Remove the most recent play from the log') - async def log_undo_play_command(self, interaction: discord.Interaction): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=False) - - try: - logger.debug(f'Undoing play {this_play.id} in Game {this_game.id}: Batter {this_play.batter}') - undo_play(this_game.id) - except AttributeError as e: - logger.error(f'Could not undo play {this_play.id} in game {this_game.id}') - - try: - last_completed = get_latest_play(this_game.id) - logger.debug(f'Undoing play {last_completed.id} in Game {this_game.id}') - undo_play(this_game.id) - except AttributeError as e: - logger.error(f'Could not undo second play in game {this_game.id}') - - latest_play = get_latest_play(this_game.id) - logger.debug(f'Latest completed play is Play {latest_play.id}; batter_to_base: {latest_play.batter_final}') - undo_subs(this_game, latest_play.play_num) - - await interaction.edit_original_response( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - @group_log.command(name='xcheck', description='Defender makes an x-check') - @app_commands.choices(position=[ - Choice(name='Pitcher', value='P'), - Choice(name='Catcher', value='C'), - Choice(name='First Base', value='1B'), - Choice(name='Second Base', value='2B'), - Choice(name='Third Base', value='3B'), - Choice(name='Shortstop', value='SS'), - Choice(name='Left Field', value='LF'), - Choice(name='Center Field', value='CF'), - Choice(name='Right Field', value='RF'), - ]) - async def log_xcheck_command(self, interaction: discord.Interaction, position: Choice[str]): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - patch_play(this_play.id, locked=False) - - def_team_id = this_game.away_team_id if this_play.inning_half == 'Bot' else this_game.home_team_id - def_team = await db_get('teams', object_id=def_team_id) - d_lineup = get_one_lineup(this_game.id, team_id=this_play.pitcher.team_id, position=position.value) - defender = await get_player(this_game, d_lineup) - patch_play(this_play.id, defender_id=d_lineup.id, check_pos=position.value) - - defender_embed = get_team_embed(f'{def_team["sname"]} {position.value}', def_team) - defender_embed.description = f'{defender["p_name"]}' - defender_embed.set_image(url=defender['image']) - embeds = [defender_embed] - - dice_embeds = sa_fielding_roll_legacy(position.value, def_team) - embeds.extend(dice_embeds) - all_embeds = [x for x in embeds if x is not None] - - await interaction.edit_original_response( - content=None, - embeds=all_embeds - ) - - hit_allowed, error_allowed, chaos_allowed = None, None, None - - view = Confirm([interaction.user], label_type='yes') - question = await interaction.channel.send(f'Did {defender["p_name"]} give up a hit?', view=view) - await view.wait() - - if view.value: - await question.delete() - view = ButtonOptions( - responders=[interaction.user], - labels=['single*', 'single**', 'double**', 'double***', 'triple'] - ) - question = await interaction.channel.send(f'Which hit did {defender["p_name"]} allow?', view=view) - - await view.wait() - - if not view.value: - await question.edit(f'Hmm...you keep thinking on it and get back to me when you\'re ready.') - return - else: - await question.delete() - - hit_allowed = view.value - else: - await question.delete() - hit_allowed = 'out' - - view = Confirm([interaction.user], label_type='yes') - question = await interaction.channel.send(f'Did {defender["p_name"]} give up an error or rare play?', view=view) - await view.wait() - - if view.value: - await question.delete() - view = ButtonOptions( - responders=[interaction.user], - labels=['1 base', '2 bases', '3 bases', 'Rare Play', None] - ) - question = await interaction.channel.send(f'What kind of error did {defender["p_name"]} allow?', view=view) - await view.wait() - - if not view.value: - await question.edit(f'Hmm...you keep thinking on it and get back to me when you\'re ready.') - return - else: - await question.delete() - - error_allowed = view.value - else: - await question.delete() - error_allowed = 'no error' - - # Not hit and no error - if hit_allowed == 'out' and error_allowed == 'no error': - if this_play.on_base_code == 0: - patch_play(this_play.id, pa=1, ab=1, outs=1) - advance_runners(this_play.id, 0) - complete_play(this_play.id) - else: - if position.value not in ['LF', 'CF', 'RF']: - view = ButtonOptions( - responders=[interaction.user], - labels=['G1', 'G2', 'G3', None if position.value != 'C' else 'FO', - None if position.value != 'C' else 'PO'] - ) - question = await interaction.channel.send(f'What was the result of the play?', view=view) - logger.info(f'obc: {this_play.on_base_code}') - await view.wait() - - logger.info(f'gameplay - view: {view} / view.value: {view.value}') - gb_type = view.value - logger.info(f'gameplay - gb_type: {gb_type}') - if not view.value: - await question.edit('Okay, we can try this again later.') - - else: - await question.delete() - - playing_in = False - batter_to_base = None - if runner_on_third(this_play) and gb_type not in ['FO', 'PO']: - view = Confirm(responders=[interaction.user], timeout=60, label_type='yes') - question = await interaction.channel.send( - f'Was the defender playing in?', view=view - ) - await view.wait() - - if view.value: - playing_in = True - else: - playing_in = False - - await question.delete() - logger.info(f'bot playing_in: {playing_in} / view.value: {view.value} / gb_type: {gb_type}') - - if gb_type == 'G1': - if (not playing_in and this_play.on_base_code == 0) or \ - (playing_in and (this_play.on_base_code in [3, 6])): - batter_to_base = gb_result_1(this_play) - - elif playing_in and this_play.on_base_code == 5: - batter_to_base = gb_result_7(this_play) - - elif (not playing_in and this_play.on_base_code in [1, 5, 7]) or \ - (playing_in and (this_play.on_base_code in [1, 4])): - batter_to_base = gb_result_2(this_play) - - elif not playing_in and this_play.on_base_code in [3, 6]: - batter_to_base = gb_result_3(this_play) - - elif this_play.on_base_code == 2: - if position.value == '3B': - this_def = '3b' - elif position.value in ['1B', '2B']: - this_def = '1b-2b' - else: - this_def = 'ss-p-c' - batter_to_base = await gb_result_12(this_play, this_def, interaction) - - elif playing_in and this_play.on_base_code == 7: - batter_to_base = gb_result_10(this_play) - - elif not playing_in and this_play.on_base_code == 4: - if position.value in ['C', '3B']: - this_def = 'c-3b' - else: - this_def = 'else' - batter_to_base = gb_result_13(this_play, this_def) - - elif gb_type == 'G2': - if (not playing_in and this_play.on_base_code == 0) or \ - (playing_in and this_play.on_base_code in [3, 6]): - batter_to_base = gb_result_1(this_play) - - elif playing_in and this_play.on_base_code == 5: - batter_to_base = gb_result_7(this_play) - - elif (not playing_in and this_play.on_base_code in [1, 4, 5, 7]) or \ - (playing_in and (this_play.on_base_code in [1, 4])): - batter_to_base = gb_result_4(this_play) - - elif not playing_in and this_play.on_base_code in [3, 6]: - if position.value in ['SS', '2B']: - to_mif = True - else: - to_mif = False - batter_to_base = gb_result_5(this_play, to_mif) - - elif playing_in and this_play.on_base_code == 7: - batter_to_base = gb_result_11(this_play) - - elif this_play.on_base_code == 2: - if position.value == '3B': - this_def = '3b' - elif position.value in ['1B', '2B']: - this_def = '1b-2b' - else: - this_def = 'ss-p-c' - batter_to_base = await gb_result_12(this_play, this_def, interaction) - - elif gb_type == 'G3': - if not playing_in and this_play.on_base_code == 0: - batter_to_base = gb_result_1(this_play) - - elif playing_in and this_play.on_base_code == 5: - batter_to_base = gb_result_7(this_play) - - elif playing_in and this_play.on_base_code == 7: - batter_to_base = gb_result_11(this_play) - - elif not playing_in and this_play.on_base_code == 2: - if position.value == '3B': - this_def = '3b' - elif position.value in ['1B', '2B']: - this_def = '1b-2b' - else: - this_def = 'ss-p-c' - batter_to_base = await gb_result_12(this_play, this_def, interaction) - - elif playing_in and this_play.on_base_code in [3, 6]: - batter_to_base = await gb_decide( - this_play, interaction, await get_player(this_play.game, this_play.on_third), 3 - ) - - else: - batter_to_base = gb_result_3(this_play) - - else: - logger.info(f'no match; log out') - patch_play(this_play.id, pa=1, ab=1, outs=1) - advance_runners(this_play.id, 0) - - complete_play(this_play.id, batter_to_base) - - else: - view = ButtonOptions(responders=[interaction.user], labels=['F1', 'F2', 'F3', None, None]) - question = await interaction.channel.send(f'What was the result of the play?', view=view) - await view.wait() - - if not view.value: - await question.delete() - await interaction.channel.send( - content=f'Just logged the x-check! Please log the resulting play to continue (e.g. ' - f'\'flyball-b\' or \'flyball-c\')' - ) - patch_play(this_play.id, locked=False) - return - - else: - await question.delete() - if view.value == 'F1': - fly_code = 'a' - elif view.value == 'F2': - fly_code = 'b' - else: - fly_code = 'c' - - await self.flyballs(interaction, this_game, this_play, fly_code) - - # Hit and error - elif hit_allowed != 'out' and error_allowed != 'no error': - patch_play(this_play.id, error=1) - if hit_allowed == 'triple': - triple(this_play, comp_play=False) - advance_runners(this_play.id, num_bases=4) - batter_to_base = 4 - elif 'double' in hit_allowed: - double_threestar(this_play, comp_play=False) - if error_allowed == 'Rare Play': - patch_play(this_play.id, outs=1) - batter_to_base = None - elif error_allowed == '1 base': - batter_to_base = 3 - elif error_allowed == '3 bases': - batter_to_base = 4 - # 2 base error is the only one handled differently between doubles - elif hit_allowed == 'double***': - batter_to_base = 4 - else: - batter_to_base = 3 - elif hit_allowed == 'single**': - single_wellhit(this_play, comp_play=False) - if error_allowed == 'Rare Play': - patch_play(this_play.id, outs=1) - batter_to_base = None - elif error_allowed == '1 base': - batter_to_base = 2 - else: - advance_runners(this_play.id, 3) - batter_to_base = 3 - else: - single_onestar(this_play, False) - if error_allowed == '2 bases': - advance_runners(this_play.id, 3, True) - batter_to_base = 3 - elif error_allowed == '1 base' or (error_allowed == 'Rare Play' and not runner_on_first(this_play)): - single_wellhit(this_play, False) - batter_to_base = 2 - patch_play(this_play.id, error=True) - else: - batter_to_base = 1 - - complete_play(this_play.id, batter_to_base=batter_to_base) - - # Either hit or error - else: - num_bases = None - if error_allowed == 'no error': - if hit_allowed == 'single*': - single_onestar(this_play) - elif hit_allowed == 'single**': - single_wellhit(this_play) - elif hit_allowed == 'double**': - double_twostar(this_play) - elif hit_allowed == 'double***': - double_threestar(this_play) - elif hit_allowed == 'triple': - triple(this_play) - elif error_allowed == 'Rare Play': - if position.value not in ['LF', 'CF', 'RF']: - view = ButtonOptions( - responders=[interaction.user], - labels=['G1', 'G2', 'G3', None if position.value != 'C' else 'FO', - None if position.value != 'C' else 'PO'] - ) - question = await interaction.channel.send(f'What was the result of the play?', view=view) - logger.info(f'obc: {this_play.on_base_code}') - await view.wait() - - logger.info(f'gameplay - view: {view} / view.value: {view.value}') - gb_type = view.value - logger.info(f'gameplay - gb_type: {gb_type}') - if not view.value: - await question.edit('Okay, we can try this again later.') - else: - await question.delete() - if gb_type == 'G1': - if runner_on_first(this_play): - await self.groundballs(interaction, this_game, this_play, 'b') - else: - await self.groundballs(interaction, this_game, this_play, 'a') - elif gb_type == 'G2': - if this_play.on_base_code != 0: - await self.groundballs(interaction, this_game, this_play, 'c') - else: - await self.groundballs(interaction, this_game, this_play, 'b') - elif gb_type == 'G3': - if this_play.on_base_code != 0: - await single_onestar(this_play) - else: - await self.groundballs(interaction, this_game, this_play, 'c') - elif gb_type == 'PO': - single_onestar(this_play) - elif gb_type == 'FO': - advance_runners(this_play.id, num_bases=1, only_forced=True) - patch_play(this_play.id, pa=1, ab=1, hit=0, error=1) - complete_play(this_play.id, batter_to_base=1) - else: - view = ButtonOptions(responders=[interaction.user], labels=['F1', 'F2', 'F3', None, None]) - question = await interaction.channel.send(f'What was the result of the play?', view=view) - await view.wait() - - if not view.value: - await question.delete() - await interaction.channel.send( - content=f'Just logged the x-check! Please log the resulting play to continue (e.g. ' - f'\'flyball-b\' or \'flyball-c\')' - ) - patch_play(this_play.id, locked=False) - return - - else: - await question.delete() - if view.value == 'F1': - fly_code = 'a' - elif view.value == 'F2': - fly_code = 'b' - else: - fly_code = 'c' - - if this_play.starting_outs == 2 or this_play.on_base_code == 0: - await self.flyballs(interaction, this_game, this_play, fly_code) - else: - if fly_code == 'a': - patch_play(this_play.id, pa=1, ab=1, outs=1) - advance_runners(this_play.id, 2) - if this_play.on_third or this_play.on_second: - patch_play(this_play.id, ab=0) - elif fly_code == 'b': - if runner_on_third(this_play): - patch_play(this_play.id, pa=1, ab=1, outs=2, on_third_final=False) - else: - await self.flyballs(interaction, this_game, this_play, fly_code, comp_play=False) - elif fly_code == 'c': - patch_play(this_play.id, pa=1, ab=1, outs=2) - if runner_on_third(this_play): - patch_play(this_play.id, on_third_final=False) - elif runner_on_second(this_play): - patch_play(this_play.id, on_second_final=False) - else: - patch_play(this_play.id, on_first_final=False) - - complete_play(this_play.id) - - else: - if position.value == 'C': - view = ButtonOptions( - responders=[interaction.user], - labels=['G1/G2/G3/SPD', 'FO', 'PO'] - ) - question = await interaction.channel.send(f'What was the result of the play?', view=view) - await view.wait() - - if not view.value: - await question.edit( - content=f'Hmm...you keep thinking on it and get back to me when you\'re ready.', - view=None - ) - return - elif view.value == 'FO': - await question.edit(content=f'**The ball dropped foul; batter swings again.**', view=None) - patch_play(this_play.id, defender_id=False, check_pos='false') - await interaction.channel.send( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - return - else: - await question.delete() - - patch_play(this_play.id, error=1) - if error_allowed == '1 base': - num_bases = 1 - elif error_allowed == '2 bases': - num_bases = 2 - elif error_allowed == '3 bases': - num_bases = 3 - - advance_runners(this_play.id, num_bases=num_bases, is_error=True) - complete_play(this_play.id, batter_to_base=num_bases) - - patch_play(this_play.id, locked=False) - await interaction.channel.send( - content=None, embed=await self.initialize_play_plus_embed(this_game, full_length=False) - ) - - # @group_log.command(name='xcheck', description='Defender makes an x-check') - # async def log_xcheck_command(self, interaction: discord.Interaction, position: Literal[ - # 'Pitcher', 'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', - # 'Center Field', 'Right Field'], hit_allowed: Literal['out', 'single*', 'single**', 'double**', - # 'double***', 'triple'], error_allowed: Literal['no error', '1 base', '2 bases', '3 bases']): - # this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - # if False in (this_game, owner_team, this_play): - # return - # - # patch_play(this_play.id, locked=False) - # - # pos = get_pos_abbrev(position) - # defender = get_one_lineup( - # this_game.id, team_id=this_play.pitcher.team_id, position=pos - # ) - # logger.info(f'defender: {defender}') - # patch_play(this_play.id, defender_id=defender.id, error=1 if error_allowed != 'no-error' else 0, check_pos=pos) - # - # # Not hit and no error - # if hit_allowed == 'out' and error_allowed == 'no error': - # await interaction.edit_original_response( - # content=f'Just logged the x-check! Please log the resulting play to continue (e.g. \'flyball-b\' or ' - # f'\'groundball-a\')' - # ) - # patch_play(this_play.id, locked=False) - # return - # - # # Hit and error - # elif hit_allowed != 'out' and error_allowed != 'no error': - # if hit_allowed == 'triple': - # triple(this_play, comp_play=False) - # batter_to_base = 4 - # elif 'double' in hit_allowed: - # double_threestar(this_play, comp_play=False) - # if error_allowed == '1 base': - # batter_to_base = 3 - # elif error_allowed == '3 bases': - # batter_to_base = 4 - # # 2 base error is the only one handled differently between doubles - # elif hit_allowed == 'double***': - # batter_to_base = 4 - # else: - # batter_to_base = 3 - # # Both singles are handled the same - # else: - # single_wellhit(this_play, comp_play=False) - # if error_allowed == '1 base': - # batter_to_base = 2 - # else: - # batter_to_base = 3 - # - # complete_play(this_play.id, batter_to_base=batter_to_base) - # - # # Either hit or error - # else: - # num_bases = None - # if error_allowed == 'no error': - # if hit_allowed == 'single*': - # single_onestar(this_play) - # elif hit_allowed == 'single**': - # single_wellhit(this_play) - # elif hit_allowed == 'double**': - # double_twostar(this_play) - # elif hit_allowed == 'double***': - # double_threestar(this_play) - # elif hit_allowed == 'triple': - # triple(this_play) - # else: - # if error_allowed == '1 base': - # num_bases = 1 - # elif error_allowed == '2 bases': - # num_bases = 2 - # elif error_allowed == '3 bases': - # num_bases = 3 - # - # advance_runners(this_play.id, num_bases=num_bases, is_error=True) - # complete_play(this_play.id, batter_to_base=num_bases) - # - # patch_play(this_play.id, locked=False) - # await interaction.edit_original_response( - # content=None, embed=await self.get_game_state_embed(this_game, full_length=False) - # ) - - group_show = app_commands.Group(name='show-card', description='Display the player card for an active player') - - @group_show.command(name='defense', description='Display a defender\'s player card') - async def show_defense_command( - self, interaction: discord.Interaction, position: Literal[ - 'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', 'Center Field', - 'Right Field']): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction, block_rollback=True) - if False in (this_game, owner_team, this_play): - return - - defender = await get_player( - game=this_game, - lineup_member=get_one_lineup( - this_game.id, team_id=this_play.pitcher.team_id, position=get_pos_abbrev(position) - ) - ) - - def_team_id = this_game.away_team_id if this_play.inning_half == 'Bot' else this_game.home_team_id - def_team = await db_get('teams', object_id=def_team_id) - embed = get_team_embed(f'{def_team["sname"]} {position}', def_team) - embed.description = f'{defender["p_name"]}' - embed.set_image(url=defender['image']) - if this_game.is_pd: - embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo']) - - await interaction.edit_original_response(content=None, embed=embed) - - @group_show.command(name='lineup', description='Display a batting team member\'s player card') - async def show_batting_team_command( - self, interaction: discord.Interaction, batting_order: Optional[int] = None, - relative_order: Optional[Literal['on-deck', 'in-the-hole']] = None): - this_game, owner_team, this_play = await self.checks_log_interaction(interaction) - if False in (this_game, owner_team, this_play): - return - - if batting_order: - lineup_member = get_one_lineup( - this_game.id, team_id=this_play.batter.team_id, batting_order=batting_order - ) - elif relative_order: - modifier = 1 if relative_order == 'on-deck' else 2 - b_order = this_play.batter.batting_order + modifier - if b_order == 10: - b_order = 1 - if b_order == 11: - b_order = 2 - lineup_member = get_one_lineup( - this_game.id, team_id=this_play.batter.team_id, batting_order=b_order - ) - else: - await interaction.edit_original_response( - content=f'You need to select either a batting order or relative order.' - ) - patch_play(this_play.id, locked=False) - return - - this_player = await get_player(game=this_game, lineup_member=lineup_member) - - embed = get_team_embed(f'{this_player["team"]["sname"]} #{lineup_member.batting_order} Batter', - this_player['team']) - embed.description = f'{this_player["name"]}' - embed.set_image(url=this_player['image']) - if this_game.is_pd: - embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo']) - - await interaction.edit_original_response(content=None, embed=embed) - - @commands.command(name='load-ai', hidden=True) - @commands.is_owner() - async def load_ai_command(self, ctx): - await ctx.send(f'{load_ai()}') - - # @commands.command(name='pentest', hidden=True) - # @commands.is_owner() - # async def pen_test_command(self, ctx, team_id: int = 3): - # this_pen = get_or_create_bullpen({'id': team_id}, self.bot) - # await ctx.send(f'{this_pen}') - - -async def setup(bot): - await bot.add_cog(Gameplay(bot))