diff --git a/ai_manager.py b/ai_manager.py index 6d6189f..285c475 100644 --- a/ai_manager.py +++ b/ai_manager.py @@ -18,20 +18,18 @@ db = SqliteDatabase( } ) -# 2022, 2023, Mario -MINOR_CARDSET_PARAMS = [('cardset_id', 8), ('cardset_id', 9), ('cardset_id', 3)] +# 2018, Mario +MINOR_CARDSET_PARAMS = [('cardset_id', 8), ('cardset_id', 13)] -# 2013, 2019, 2022, 2023, Mario +# 2018, 2023, Mario, 2013 MAJOR_CARDSET_PARAMS = [ - ('cardset_id', 8), ('cardset_id', 6), ('cardset_id', 5), - ('cardset_id', 3), ('cardset_id', 4), - ('cardset_id', 9), ('cardset_id', 10) + ('cardset_id', 9), ('cardset_id', 8), ('cardset_id', 6), ('cardset_id', 13) ] # 2008, 2012, 2013, 2016, 2019, 2021, 2022, 2023, Mario HOF_CARDSET_PARAMS = [ ('cardset_id', 1), ('cardset_id', 3), ('cardset_id', 4), ('cardset_id', 5), ('cardset_id', 6), ('cardset_id', 7), - ('cardset_id', 8), ('cardset_id', 9), ('cardset_id', 10), ('cardset_id', 11), ('cardset_id', 12) + ('cardset_id', 8), ('cardset_id', 9), ('cardset_id', 10), ('cardset_id', 11), ('cardset_id', 12), ('cardset_id', 13) ] # 2008, 2012, 2013, 2016 @@ -223,101 +221,104 @@ async def build_lineup_graded(team_object: dict, vs_hand: str, league_name: str, return batting_order -async def build_lineup(team_object: dict, game_id: int, league_name: str, vs_hand: str = 'r') -> list: - players = { - 'C': None, - '1B': None, - '2B': None, - '3B': None, - 'SS': None, - 'LF': None, - 'CF': None, - 'RF': None, - 'DH': None - } - p_names = [] - rest_name = None +async def build_lineup(team_object: dict, game_id: int, league_name: str, sp_name: str, vs_hand: str = 'r') -> list: + # players = { + # 'C': None, + # '1B': None, + # '2B': None, + # '3B': None, + # 'SS': None, + # 'LF': None, + # 'CF': None, + # 'RF': None, + # 'DH': None + # } + # p_names = [] + # rest_name = None + # + # set_params = [('cardset_id_exclude', 2)] + # if team_object['id'] == 58: + # set_params = [] + # elif league_name == 'minor-league': + # set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) + # elif league_name == 'major-league': + # set_params = copy.deepcopy(MAJOR_CARDSET_PARAMS) + # elif league_name == 'hall-of-fame': + # set_params = copy.deepcopy(HOF_CARDSET_PARAMS) + # elif 'gauntlet-1' in league_name: + # set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) + # elif 'gauntlet-2' in league_name: + # set_params = random.sample(GAUNTLET2_PARAMS, 2) + # + # # Pull players sorted by current cost + # try: + # params = [ + # ('mlbclub', team_object['lname']), ('pos_include', 'C'), ('pos_include', '1B'), ('pos_include', '2B'), + # ('pos_include', '3B'), ('pos_include', 'SS'), ('pos_include', 'LF'), ('pos_include', 'CF'), + # ('pos_include', 'RF'), ('pos_include', 'DH'), ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 50) + # ] + # params.extend(set_params) + # p_query = await db_get( + # endpoint='players', + # params=params, + # timeout=10 + # ) + # all_players = p_query['players'] + # except ConnectionError as e: + # raise ConnectionError(f'Error pulling batters for the {team_object["lname"]}. Cal help plz.') + # + # logging.info(f'build_lineup - eligible batter count: {len(all_players)}') + # + # # Choose starting nine & position + # # In order of cost: + # # Try to add to pos_1; if unavailable, try remaining pos; if unavailable, add to DH + # # If all pos unavailable; note player's pos_1 and check if incumbent can move; if so, check for new incumbent + # # and recurse + # # If not possible, pass player and continue + # for guy in all_players: + # placed = False + # if guy['p_name'] not in p_names and guy['p_name'] != rest_name: + # for pos in [ + # guy['pos_1'], guy['pos_2'], guy['pos_3'], guy['pos_4'], guy['pos_5'], guy['pos_6'], guy['pos_7'], + # guy['pos_8'] + # ]: + # if pos is None or pos in ['SP', 'RP', 'CP']: + # break + # + # if random.randint(1, 10) == 10 and rest_name is None and False: + # logging.info(f'Resting {guy["p_name"]} in game {game_id}') + # rest_name = guy['p_name'] + # elif players[pos] is None: + # players[pos] = guy + # p_names.append(guy["p_name"]) + # placed = True + # break + # + # if not placed and rest_name != guy['p_name']: + # if players['DH'] is None: + # players['DH'] = guy + # p_names.append(guy["p_name"]) + # else: + # logging.info(f'build_lineup - could not place {guy["p_name"]} in {team_object["sname"]} lineup') + # else: + # logging.info(f'build_lineup - {guy["p_name"]} already in lineup') + # + # if None in players.values(): + # bad_pos = {x for x in players if players[x] is None} + # raise ValueError(f'Could not find a {bad_pos} for the {team_object["sname"]}') + # + # logging.info(f'build_lineup - {players}') + # + # # Sort players into lineup + # # Pseudo-random? Patterns? Something to mix up lineups + # # 421356789 or [123 (rand)][456 (rand)][789 (rand)] (optional: chance to flip 3/4 and 6/7) + # + # # [ (, ), (, ), etc. ] + # sorted_players = sorted(players.items(), key=lambda x: x[1]['cost'], reverse=True) - set_params = [('cardset_id_exclude', 2)] - if team_object['id'] == 58: - set_params = [] - elif league_name == 'minor-league': - set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) - elif league_name == 'major-league': - set_params = copy.deepcopy(MAJOR_CARDSET_PARAMS) - elif league_name == 'hall-of-fame': - set_params = copy.deepcopy(HOF_CARDSET_PARAMS) - elif 'gauntlet-1' in league_name: - set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) - elif 'gauntlet-2' in league_name: - set_params = random.sample(GAUNTLET2_PARAMS, 2) - - # Pull players sorted by current cost - try: - params = [ - ('mlbclub', team_object['lname']), ('pos_include', 'C'), ('pos_include', '1B'), ('pos_include', '2B'), - ('pos_include', '3B'), ('pos_include', 'SS'), ('pos_include', 'LF'), ('pos_include', 'CF'), - ('pos_include', 'RF'), ('pos_include', 'DH'), ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 50) - ] - params.extend(set_params) - p_query = await db_get( - endpoint='players', - params=params, - timeout=10 - ) - all_players = p_query['players'] - except ConnectionError as e: - raise ConnectionError(f'Error pulling batters for the {team_object["lname"]}. Cal help plz.') - - logging.info(f'build_lineup - eligible batter count: {len(all_players)}') - - # Choose starting nine & position - # In order of cost: - # Try to add to pos_1; if unavailable, try remaining pos; if unavailable, add to DH - # If all pos unavailable; note player's pos_1 and check if incumbent can move; if so, check for new incumbent - # and recurse - # If not possible, pass player and continue - for guy in all_players: - placed = False - if guy['p_name'] not in p_names and guy['p_name'] != rest_name: - for pos in [ - guy['pos_1'], guy['pos_2'], guy['pos_3'], guy['pos_4'], guy['pos_5'], guy['pos_6'], guy['pos_7'], - guy['pos_8'] - ]: - if pos is None or pos in ['SP', 'RP', 'CP']: - break - - if random.randint(1, 10) == 10 and rest_name is None and False: - logging.info(f'Resting {guy["p_name"]} in game {game_id}') - rest_name = guy['p_name'] - elif players[pos] is None: - players[pos] = guy - p_names.append(guy["p_name"]) - placed = True - break - - if not placed and rest_name != guy['p_name']: - if players['DH'] is None: - players['DH'] = guy - p_names.append(guy["p_name"]) - else: - logging.info(f'build_lineup - could not place {guy["p_name"]} in {team_object["sname"]} lineup') - else: - logging.info(f'build_lineup - {guy["p_name"]} already in lineup') - - if None in players.values(): - bad_pos = {x for x in players if players[x] is None} - raise ValueError(f'Could not find a {bad_pos} for the {team_object["sname"]}') - - logging.info(f'build_lineup - {players}') - - # Sort players into lineup - # Pseudo-random? Patterns? Something to mix up lineups - # 421356789 or [123 (rand)][456 (rand)][789 (rand)] (optional: chance to flip 3/4 and 6/7) - lineups = [] - - # [ (, ), (, ), etc. ] - sorted_players = sorted(players.items(), key=lambda x: x[1]['cost'], reverse=True) + l_query = await db_get(f'teams/{team_object["id"]}/lineup/{league_name}?pitcher_name={sp_name}') + sorted_players = l_query['array'] + logging.info(f'sorted_players: {sorted_players}') grp_1 = sorted_players[:3] grp_2 = sorted_players[3:6] @@ -326,15 +327,18 @@ async def build_lineup(team_object: dict, game_id: int, league_name: str, vs_han random.shuffle(grp_2) random.shuffle(grp_3) + lineups = [] i = 1 for x in [grp_1, grp_2, grp_3]: + logging.info(f'group: {x}') for y in x: - card_id = await get_or_create_card(y[1], team_object) + logging.info(f'y: {y}') + card_id = await get_or_create_card(y[1]['player'], team_object) lineups.append({ 'game_id': game_id, 'team_id': team_object['id'], - 'player_id': y[1]['player_id'], + 'player_id': y[1]['player']['player_id'], 'card_id': card_id, 'position': y[0], 'batting_order': i, @@ -348,83 +352,79 @@ async def build_lineup(team_object: dict, game_id: int, league_name: str, vs_han async def get_starting_pitcher(team_object: dict, game_id: int, is_home: bool, league_name: str = None) -> dict: - set_params = [('cardset_id_exclude', 2)] - if league_name == 'minor-league': - set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) - elif league_name == 'major-league': - set_params = copy.deepcopy(MAJOR_CARDSET_PARAMS) - elif league_name == 'hall-of-fame': - set_params = copy.deepcopy(HOF_CARDSET_PARAMS) - elif league_name == 'gauntlet-1': - set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) - elif 'gauntlet-2' in league_name: - set_params = random.sample(GAUNTLET2_PARAMS) - - params = [ - ('mlbclub', team_object['lname']), ('pos_include', 'SP'), ('pos_exclude', 'RP'), - ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5) - ] - counter = 0 - logging.info(f'params: {params}') - while counter < 2: - logging.info(f'counter: {counter}') - counter += 1 - # Pull starters sorted by current cost - logging.info(f'counter: {counter} / params: {params}') - try: - params.extend(set_params) - pitchers = await db_get( - endpoint='players', - params=params, - timeout=10 - ) - logging.info(f'pitchers: {pitchers}') - except ConnectionError as e: - logging.error(f'Could not get pitchers for {team_object["lname"]}: {e}') - raise ConnectionError(f'Error pulling starting pitchers for the {team_object["lname"]}. Cal help plz.') - - if pitchers['count'] == 0: - logging.info(f'pitchers is None') - del params - params = [ - ('mlbclub', team_object['lname']), ('pos_include', 'SP'), - ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5) - ] - else: - break - - logging.info(f'build_lineup - eligible starting pitcher count: {len(pitchers)}') - if pitchers['count'] == 0: - raise DatabaseError(f'Could not find any SP for {team_object["abbrev"]}. Seems like a Cal issue.') + # set_params = [('cardset_id_exclude', 2)] + # if league_name == 'minor-league': + # set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) + # elif league_name == 'major-league': + # set_params = copy.deepcopy(MAJOR_CARDSET_PARAMS) + # elif league_name == 'hall-of-fame': + # set_params = copy.deepcopy(HOF_CARDSET_PARAMS) + # elif league_name == 'gauntlet-1': + # set_params = copy.deepcopy(MINOR_CARDSET_PARAMS) + # elif 'gauntlet-2' in league_name: + # set_params = random.sample(GAUNTLET2_PARAMS) + # + # params = [ + # ('mlbclub', team_object['lname']), ('pos_include', 'SP'), ('pos_exclude', 'RP'), + # ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5) + # ] + # counter = 0 + # logging.info(f'params: {params}') + # while counter < 2: + # logging.info(f'counter: {counter}') + # counter += 1 + # # Pull starters sorted by current cost + # logging.info(f'counter: {counter} / params: {params}') + # try: + # params.extend(set_params) + # pitchers = await db_get( + # endpoint='players', + # params=params, + # timeout=10 + # ) + # logging.info(f'pitchers: {pitchers}') + # except ConnectionError as e: + # logging.error(f'Could not get pitchers for {team_object["lname"]}: {e}') + # raise ConnectionError(f'Error pulling starting pitchers for the {team_object["lname"]}. Cal help plz.') + # + # if pitchers['count'] == 0: + # logging.info(f'pitchers is None') + # del params + # params = [ + # ('mlbclub', team_object['lname']), ('pos_include', 'SP'), + # ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5) + # ] + # else: + # break + # + # logging.info(f'build_lineup - eligible starting pitcher count: {len(pitchers)}') + # if pitchers['count'] == 0: + # raise DatabaseError(f'Could not find any SP for {team_object["abbrev"]}. Seems like a Cal issue.') d_100 = random.randint(1, 100) - starter = None if is_home: if d_100 <= 30: - starter = pitchers['players'][0] - elif d_100 <= 55 and pitchers['count'] > 1: - starter = pitchers['players'][1] - elif d_100 <= 75 and pitchers['count'] > 2: - starter = pitchers['players'][2] - elif d_100 <= 90 and pitchers['count'] > 3: - starter = pitchers['players'][3] - elif pitchers['count'] == 5: - starter = pitchers['players'][4] + sp_rank = 1 + elif d_100 <= 55: + sp_rank = 2 + elif d_100 <= 75: + sp_rank = 3 + elif d_100 <= 90: + sp_rank = 4 else: - starter = pitchers['players'][0] + sp_rank = 5 else: if d_100 <= 50: - starter = pitchers['players'][0] - elif d_100 <= 75 and pitchers['count'] > 1: - starter = pitchers['players'][1] - elif d_100 <= 85 and pitchers['count'] > 2: - starter = pitchers['players'][2] - elif d_100 <= 95 and pitchers['count'] > 3: - starter = pitchers['players'][3] - elif pitchers['count'] == 5: - starter = pitchers['players'][4] + sp_rank = 1 + elif d_100 <= 75: + sp_rank = 2 + elif d_100 <= 85: + sp_rank = 3 + elif d_100 <= 95: + sp_rank = 4 else: - starter = pitchers['players'][0] + sp_rank = 5 + starter = await db_get(f'teams/{team_object["id"]}/sp/{league_name}?sp_rank={sp_rank}') # get player card; create one if none found card_id = await get_or_create_card(starter, team_object) diff --git a/cogs/gameplay.py b/cogs/gameplay.py index fce6926..e20baf7 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -20,7 +20,7 @@ from dice import sa_fielding_roll from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, IMAGES, \ get_team_embed, Confirm, get_pos_abbrev, SBA_COLOR, get_roster_lineups, Question, give_packs, send_to_channel, \ get_channel, get_or_create_role, team_role, get_cal_user, get_card_embeds, ButtonOptions, get_ratings_guide, \ - get_team_by_owner, get_roster_sheet, get_role + get_team_by_owner, get_roster_sheet, get_role, player_desc, player_pcard, player_bcard from gameplay_helpers import * from db_calls import db_get, db_patch, db_post, db_delete, get_team_by_abbrev from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, get_sba_team, get_sba_player, \ @@ -223,8 +223,10 @@ class Gameplay(commands.Cog): 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) + logging.info(f'away_lineup: {away_lineup}') + logging.info(f'home_lineup: {home_lineup}') - if not away_lineup or not home_lineup: + if len(away_lineup) < 200 or len(home_lineup) < 200: game_state = { 'error': True, 'away_lineup': away_lineup, @@ -237,7 +239,7 @@ class Gameplay(commands.Cog): else: logging.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') - logging.info(f'pitcher: {pitcher}') + logging.debug(f'pitcher: {pitcher}') curr_play = post_play({ 'game_id': game.id, 'play_num': 1, @@ -386,10 +388,7 @@ class Gameplay(commands.Cog): # embed.add_field(name='Matchup', value=f'Pitcher: \nvs\nBatter: ', inline=False) embed.add_field(name='Pitcher', value=f'{pitcher_string}') embed.add_field(name='Batter', value=f'{batter_string}') - if game_state['batter']['image2']: - embed.set_image(url=game_state["batter"]["image2"]) - else: - embed.set_image(url=game_state["batter"]["image"]) + embed.set_image(url=player_bcard(game_state['batter'])) baserunner_string = '' if game_state['curr_play'].on_first: @@ -433,7 +432,7 @@ class Gameplay(commands.Cog): embed.add_field( name='SUBSTITUTION', value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in ' - f'{ai_data["sub"]["description"]} to pitch.' + f'{player_desc(ai_data["sub"])} to pitch' ) # AI Team is batting @@ -967,10 +966,12 @@ class Gameplay(commands.Cog): # ) @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', 'Major League', 'Hall of Fame'], - away_team_abbrev: str, home_team_abbrev: str, num_innings: Literal[9, 3]): + 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) @@ -1036,6 +1037,7 @@ class Gameplay(commands.Cog): 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( @@ -1045,34 +1047,38 @@ class Gameplay(commands.Cog): if 'Minor' in league: league_name = 'minor-league' - 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' + await interaction.edit_original_response( + content=f'Bonus star for speed running the Minor Leagues. The Major League campaign will release soon!') + return + # 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'], @@ -1091,27 +1097,39 @@ class Gameplay(commands.Cog): ) away_role = await team_role(interaction, away_team) home_role = await team_role(interaction, home_team) + all_lineups = [] - # Get AI Lineup - try: - await interaction.edit_original_response( - content=f'I am getting a lineup card from the {ai_team["sname"]}...' - ) - - logging.info(f'new-game - calling lineup for {ai_team["abbrev"]}') - all_lineups = await ai_manager.build_lineup(ai_team, this_game.id, league_name) - logging.info(f'new-game - got lineup for {ai_team["abbrev"]}') - - except Exception as e: - patch_game(this_game.id, active=False) - logging.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?' + # 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']: + logging.error( + f'Card_id {sp_card_id} does not belong to {human_team["abbrev"]} in Game {this_game.id}' ) + 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']]) + if not l_check['legal']: + 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 get 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( @@ -1130,11 +1148,12 @@ class Gameplay(commands.Cog): 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 **{this_card["player"]["description"]}**:\n\n' - f'{this_card["player"]["image"]}' + 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: @@ -1147,6 +1166,29 @@ class Gameplay(commands.Cog): ) return + # Get AI Lineup + try: + await interaction.edit_original_response( + content=f'I am getting a lineup card from the {ai_team["sname"]}...' + ) + + logging.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) + logging.info(f'new-game - got lineup for {ai_team["abbrev"]}') + + except Exception as e: + patch_game(this_game.id, active=False) + logging.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 + logging.debug(f'Setting lineup for {ai_team["sname"]} in PD game') logging.info(f'lineups: {all_lineups}') post_lineups(all_lineups) @@ -1472,7 +1514,7 @@ class Gameplay(commands.Cog): this_card = await db_get(f'cards', object_id=starter['card_id']) await interaction.channel.send( - content=f'The {opponent["sname"]} are starting **{this_card["player"]["description"]}**:\n\n' + content=f'The {opponent["sname"]} are starting **{player_desc(this_card["player"])}**:\n\n' f'{this_card["player"]["image"]}' ) @@ -1529,7 +1571,7 @@ class Gameplay(commands.Cog): get_pitching_decisions(this_game) await ctx.send(random_conf_gif()) - @app_commands.command(name='endgame', description='End game in this channel') + @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() @@ -1564,6 +1606,13 @@ class Gameplay(commands.Cog): Top 9th inning or earlier and not 10-run lead """ + if latest_play is None: + patch_game(this_game.id, active=False) + await interaction.edit_original_response( + content='Roger dodger - it is game over.' + ) + return + valid_end = False if latest_play.starting_outs == 0: if latest_play.inning_half == 'top': @@ -1991,19 +2040,18 @@ class Gameplay(commands.Cog): ) @app_commands.command( - name='readlineup', + name='read-lineup', description='Import a saved lineup directly from the team sheet for PD games' ) @app_commands.describe( team_abbrev='The 2- to 4-digit abbreviation for the team being set', roster='Which roster to pull from your sheet?', - lineup='Which handedness lineup are you using?', - sp_card_id='Light gray number to the left of the pitcher\'s name on your depth chart' + 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, team_abbrev: str, roster: Literal['Primary', 'Secondary', 'Ranked'], - lineup: Literal['v Right', 'v Left'], sp_card_id: int): + 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!') @@ -2029,8 +2077,8 @@ class Gameplay(commands.Cog): ) return - existing_lineups = await get_team_lineups(this_game.id, lineup_team['id']) - if existing_lineups: + existing_lineups = await get_team_lineups(this_game.id, lineup_team['id'], as_string=False) + 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.' ) @@ -2089,55 +2137,53 @@ class Gameplay(commands.Cog): else: patch_game(this_game.id, home_roster_num=roster_num) - if lineup_team['is_ai']: - starter = starting_pitcher(lineup_team, self.bot, True if this_game.ai_team == 'home' else False) - this_card = await db_get(f'cards', object_id=int(starter)) - all_lineups.append({ - 'game_id': this_game.id, - 'team_id': lineup_team['id'], - 'player_id': this_card['player']['player_id'], - 'card_id': starter, - 'position': 'P', - 'batting_order': 10, - 'after_play': 0 - }) - all_pos.append('P') - else: - this_card = await db_get(f'cards', object_id=sp_card_id) - logging.debug(f'this_card: {this_card}') - - if this_card['team']['id'] != lineup_team['id']: - logging.error( - f'Card_id {sp_card_id} does not belong to {lineup_team["abbrev"]} in Game {this_game.id}' - ) - await interaction.channel.send( - f'Uh oh. Card ID {sp_card_id} is {this_card["player"]["p_name"]} and belongs to ' - f'{this_card["team"]["sname"]}. Will you double check that before we get started?') - return - - else: - card_ids.append(str(sp_card_id)) - all_lineups.append({ - 'game_id': this_game.id, - 'team_id': lineup_team['id'], - 'player_id': this_card['player']['player_id'], - 'card_id': sp_card_id, - 'position': 'P', - 'batting_order': 10, - 'after_play': 0 - }) - all_pos.append('P') + # if lineup_team['is_ai']: + # starter = starting_pitcher(lineup_team, self.bot, True if this_game.ai_team == 'home' else False) + # this_card = await db_get(f'cards', object_id=int(starter)) + # all_lineups.append({ + # 'game_id': this_game.id, + # 'team_id': lineup_team['id'], + # 'player_id': this_card['player']['player_id'], + # 'card_id': starter, + # 'position': 'P', + # 'batting_order': 10, + # 'after_play': 0 + # }) + # all_pos.append('P') + # else: + # this_card = await db_get(f'cards', object_id=sp_card_id) + # logging.debug(f'this_card: {this_card}') + # + # if this_card['team']['id'] != lineup_team['id']: + # logging.error( + # f'Card_id {sp_card_id} does not belong to {lineup_team["abbrev"]} in Game {this_game.id}' + # ) + # await interaction.channel.send( + # f'Uh oh. Card ID {sp_card_id} is {this_card["player"]["p_name"]} and belongs to ' + # f'{this_card["team"]["sname"]}. Will you double check that before we get started?') + # return + # + # else: + # card_ids.append(str(sp_card_id)) + # all_lineups.append({ + # 'game_id': this_game.id, + # 'team_id': lineup_team['id'], + # 'player_id': this_card['player']['player_id'], + # 'card_id': sp_card_id, + # 'position': 'P', + # 'batting_order': 10, + # 'after_play': 0 + # }) + # all_pos.append('P') # Check roster legality if this_game.game_type in ['major-league', 'hall-of-fame']: - l_string = "&card_id=".join(card_ids) - legality = await db_post(f'cards/legal-check/ranked?card_id={l_string}') - if legality['count'] > 0: - il_string = "\n- ".join(legality['bad_cards']) + l_check = await legal_check(card_ids) + 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'- {il_string}' + f'- {l_check["error_string"]}' ) return @@ -2159,12 +2205,6 @@ class Gameplay(commands.Cog): # return # else: - if 'P' not in all_pos: - await interaction.channel.send( - content=f'Please enter the Starting pitcher using the `/starting-pitcher` command' - ) - return - try: await interaction.channel.send(content=None, embed=await self.get_game_state_embed(this_game)) except IntegrityError as e: @@ -2749,6 +2789,7 @@ class Gameplay(commands.Cog): # Safe at home and third else: + batter_to_base = 3 await question.delete() # No: Safe at home? @@ -2938,12 +2979,17 @@ class Gameplay(commands.Cog): advance_runners(this_play.id, 0) if running_type == 'stolen-base': - if to_base == 'Home' and this_play.on_third: + 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 ) @@ -2978,10 +3024,14 @@ class Gameplay(commands.Cog): return if running_type == 'steal-plus-overthrow': - if to_base == 'Home' and this_play.on_third: + 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: @@ -3018,13 +3068,18 @@ class Gameplay(commands.Cog): patch_play(this_play.id, error=1) elif running_type == 'caught-stealing': - if to_base == 'Home' and this_play.on_third: + 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 diff --git a/cogs/players.py b/cogs/players.py index bb1384d..79f875e 100644 --- a/cogs/players.py +++ b/cogs/players.py @@ -515,7 +515,7 @@ class Players(commands.Cog): await interaction.response.defer() c_query = await db_get('cards', object_id=card_id) if c_query: - c_string = f'Card ID {card_id} is a {c_query["player"]["description"]}' + c_string = f'Card ID {card_id} is a {helpers.player_desc(c_query["player"])}' if c_query['team'] is not None: c_string += f' owned by the {c_query["team"]["sname"]}' if c_query["pack"] is not None: diff --git a/gameplay_helpers.py b/gameplay_helpers.py index ddbfa55..138e6ae 100644 --- a/gameplay_helpers.py +++ b/gameplay_helpers.py @@ -4,7 +4,7 @@ import random import db_calls_gameplay from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, patch_play, advance_runners, \ complete_play, get_team_lineups, get_or_create_bullpen, get_player, get_sheets, make_sub -from db_calls import db_get +from db_calls import db_get, db_post def single_onestar(this_play: StratPlay, comp_play: bool = True): @@ -163,3 +163,15 @@ def get_pitcher(this_game: StratGame, this_play: StratPlay): p_team_id = this_game.home_team_id return db_calls_gameplay.get_one_lineup(this_game.id, team_id=p_team_id, position='P', active=True) + +async def legal_check(card_ids: list): + l_string = "&card_id=".join(card_ids) + legality = await db_post(f'cards/legal-check/ranked?card_id={l_string}') + + r_val = {'legal': True, 'error_string': None} + if legality['count'] > 0: + r_val['legal'] = False + r_val['error_string'] = "\n- ".join(legality['bad_cards']) + + return r_val + diff --git a/gauntlets.py b/gauntlets.py index e8b2de2..6ea9e36 100644 --- a/gauntlets.py +++ b/gauntlets.py @@ -295,9 +295,9 @@ async def run_draft(interaction: discord.Interaction, main_team, this_event, dra for y in all_players: if include_links: - name_string = f'[{y["description"]}]({y["image"]})' + name_string = f'[{helpers.player_desc(y)}]({y["image"]})' else: - name_string = f'{y["description"]}' + name_string = f'{helpers.player_desc(y)}' all_str[y['rarity']['name']] += f'{name_string}\n' for z in helpers.get_all_pos(y): all_str[z] += f'{name_string}\n' diff --git a/helpers.py b/helpers.py index 85dbb4f..583acb9 100644 --- a/helpers.py +++ b/helpers.py @@ -3008,3 +3008,27 @@ async def confirm_pack_purchase(interaction, owner_team, num_packs, total_cost, return None else: return question + + +def player_desc(this_player) -> str: + if this_player['p_name'] in this_player['description']: + return this_player['description'] + return f'{this_player["description"]} {this_player["p_name"]}' + + +def player_pcard(this_player): + if 'pitching' in this_player['image']: + return this_player['image'] + elif 'pitching' in this_player['image2']: + return this_player['image2'] + else: + return None + + +def player_bcard(this_player): + if 'batting' in this_player['image']: + return this_player['image'] + elif 'batting' in this_player['image2']: + return this_player['image2'] + else: + return None