diff --git a/cogs/gameplay.py b/cogs/gameplay.py index 085c759..16db941 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -8,7 +8,8 @@ from discord.ext import commands, tasks import pygsheets from api_calls import db_get -from command_logic.logic_gameplay import advance_runners, bunts, complete_game, doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, hit_by_pitch, homeruns, is_game_over, popouts, show_defense_cards, singles, strikeouts, triples, undo_play, walks +from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, popouts, show_defense_cards, singles, strikeouts, triples, undo_play, update_game_settings, walks +from dice import ab_roll from exceptions import GameNotFoundException, TeamNotFoundException, PlayNotFoundException, GameException, log_exception from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, get_channel, team_role, user_has_role, random_gif, random_from_list @@ -18,7 +19,7 @@ from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check from in_game.gameplay_models import Lineup, Play, Session, engine, player_description, select, Game from in_game.gameplay_queries import get_and_cache_position, get_channel_game_or_none, get_active_games_by_team, get_game_lineups, get_team_or_none, get_card_or_none -from utilities.buttons import Confirm, ask_confirm +from utilities.buttons import Confirm, ScorebugButtons, ask_confirm CLASSIC_EMBED = True @@ -51,7 +52,9 @@ class Gameplay(commands.Cog): await ctx.send(f'{error[:1600]}') async def post_play(self, session: Session, interaction: discord.Interaction, this_play: Play, buffer_message: str = None): + logger.info(f'post_play - Posting new play') if is_game_over(this_play): + logger.info(f'Game {this_play.game.id} seems to be over') await interaction.edit_original_response(content=f'Looks like this one is over!') submit_game = await ask_confirm( interaction=interaction, @@ -61,6 +64,7 @@ class Gameplay(commands.Cog): ) if submit_game: + logger.info(f'post_play - is_game_over - {interaction.user.display_name} rejected game completion') await complete_game(session, interaction, this_play) return else: @@ -74,22 +78,45 @@ class Gameplay(commands.Cog): await self.post_play(session, interaction, this_play) await interaction.channel.send(content=f'I let Cal know his bot is stupid') - elif buffer_message is not None: + scorebug_buttons, this_ab_roll = None, None + + if this_play.game.roll_buttons and interaction.user.id in [this_play.game.away_team.gmid, this_play.game.home_team.gmid]: + scorebug_buttons = ScorebugButtons(this_play) + + if this_play.on_base_code == 0 and this_play.game.auto_roll and not this_play.batter.team.is_ai: + this_ab_roll = ab_roll(this_play.batter.team, this_play.game, allow_chaos=False) + scorebug_buttons = None + + scorebug_embed = await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED) + if this_ab_roll is not None and this_ab_roll.d_six_one > 3: + scorebug_embed.set_image(url=this_play.pitcher.player.pitcher_card_url) + + if buffer_message is not None: await interaction.edit_original_response( content=buffer_message ) await interaction.channel.send( content=None, - embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED) + embed=scorebug_embed, + view=scorebug_buttons ) else: await interaction.edit_original_response( content=None, - embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED) - ) + embed=scorebug_embed, + view=scorebug_buttons + ) + + if this_ab_roll is not None: + await interaction.channel.send( + content=None, + embeds=this_ab_roll.embeds + ) async def complete_and_post_play(self, session: Session, interaction: discord.Interaction, this_play: Play, buffer_message: str = None): next_play = complete_play(session, this_play) + logger.info(f'Completed play {this_play.id}') + await self.post_play(session, interaction, next_play, buffer_message) group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game') @@ -272,7 +299,8 @@ class Gameplay(commands.Cog): away_role = await team_role(interaction, away_team) home_role = await team_role(interaction, home_team) - embed = this_game.get_scorebug_embed(session).clear_fields() + embed = await get_scorebug_embed(session, this_game) + embed.clear_fields() embed.add_field( name=f'{ai_team.abbrev} Lineup', value=this_game.team_lineup(session, ai_team) @@ -296,7 +324,7 @@ class Gameplay(commands.Cog): try: await ctx.send( content=None, - embed=this_game.get_scorebug_embed(session, full_length=True) + embed=await get_scorebug_embed(session, this_game, full_length=True) ) except Exception as e: logger.error(f'Unable to display scorebug while forcing game to end: {e}') @@ -385,7 +413,8 @@ class Gameplay(commands.Cog): if batter.position != 'DH': await get_and_cache_position(session, batter.card, batter.position) - await interaction.edit_original_response(content=None, embed=this_game.get_scorebug_embed(session)) + this_play = this_game.initialize_play(session) + await self.post_play(session, interaction, this_play) @app_commands.command(name='gamestate', description='Post the current game state') async def gamestate_command(self, interaction: discord.Interaction, include_lineups: bool = False): @@ -399,10 +428,25 @@ class Gameplay(commands.Cog): ) return - await interaction.edit_original_response( - content=None, - embed=this_game.get_scorebug_embed(session, full_length=include_lineups) - ) + this_play = this_game.current_play_or_none(session) + await self.post_play(session, interaction, this_play) + + @app_commands.command(name='settings-ingame', description='Change in-game settings') + @app_commands.describe( + roll_buttons='Display the "Roll AB" and "Check Jump" buttons along with the scorebug', + auto_roll='When there are no baserunners, automatically roll the next AB' + ) + async def game_settings_command(self, interaction: discord.Interaction, roll_buttons: bool = None, auto_roll: bool = None): + with Session(engine) as session: + this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='settings-ingame') + + await interaction.edit_original_response(content=None, embed=await update_game_settings( + session, + interaction, + this_game, + roll_buttons=roll_buttons, + auto_roll=auto_roll + )) group_log = app_commands.Group(name='log', description='Log a play in this channel\'s game') @@ -427,10 +471,10 @@ class Gameplay(commands.Cog): with Session(engine) as session: this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log single') - logger.info(f'log single {single_type} - this_play: {this_play}') this_play = await singles(session, interaction, this_play, single_type) + logger.info(f'log single {single_type} - this_play: {this_play}') - await self.complete_and_post_play(session, interaction, this_play, buffer_message='Double logged' if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped') else None) + await self.complete_and_post_play(session, interaction, this_play, buffer_message='Single logged' if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped') else None) # complete_play(session, this_play) @@ -438,12 +482,12 @@ class Gameplay(commands.Cog): # await interaction.edit_original_response(content='Single logged') # await interaction.channel.send( # content=None, - # embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED) + # embed=await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED) # ) # else: # await interaction.edit_original_response( # content=None, - # embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED) + # embed=await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED) # ) @group_log.command(name='double', description='Doubles: **, ***, uncapped') @@ -515,6 +559,23 @@ class Gameplay(commands.Cog): this_play = await hit_by_pitch(session, interaction, this_play) await self.complete_and_post_play(session, interaction, this_play) + + @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']): + with Session(engine) as session: + this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log hit-by-pitch') + + if this_play.on_base_code == 0: + await interaction.edit_original_response( + content=f'There cannot be chaos when the bases are empty.' + ) + return + + logger.info(f'log chaos - this_play: {this_play}') + this_play = await chaos(session, interaction, this_play, chaos_type) + + await self.complete_and_post_play(session, interaction, this_play) + @group_log.command(name='bunt', description='Bunts: sacrifice, bad, popout, double-play, defense') async def log_sac_bunt(self, interaction: discord.Interaction, bunt_type: Literal['sacrifice', 'bad', 'popout', 'double-play', 'defense']): @@ -548,6 +609,7 @@ class Gameplay(commands.Cog): await self.post_play(session, interaction, this_play) 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: DEFENSE_LITERAL): with Session(engine) as session: diff --git a/cogs/owner.py b/cogs/owner.py index 808d86c..850eea3 100644 --- a/cogs/owner.py +++ b/cogs/owner.py @@ -107,11 +107,14 @@ class Owner(commands.Cog): elif spec == '!': fmt = await ctx.bot.tree.sync() await ctx.send(f'Synced {len(fmt)} commands globally.') - ctx.bot.tree.clear_commands(guild=ctx.guild) - await ctx.send(f'Cleared all local commands.') + if len(fmt) > 0: + ctx.bot.tree.copy_global_to(guild=ctx.guild) fmt = await ctx.bot.tree.sync(guild=ctx.guild) await ctx.send(f'Synced global commands to this guild.') + + ctx.bot.tree.clear_commands(guild=ctx.guild) + await ctx.send(f'Cleared all local commands.') else: fmt = await ctx.bot.tree.sync() diff --git a/command_logic/logic_gameplay.py b/command_logic/logic_gameplay.py index 56eede7..c08ed8a 100644 --- a/command_logic/logic_gameplay.py +++ b/command_logic/logic_gameplay.py @@ -9,9 +9,9 @@ from typing import Literal from api_calls import db_delete, db_get, db_post from exceptions import * -from helpers import DEFENSE_LITERAL, get_channel +from helpers import DEFENSE_LITERAL, SBA_COLOR, get_channel from in_game.game_helpers import legal_check -from in_game.gameplay_models import Game, Lineup, Team, Play +from in_game.gameplay_models import BattingCard, Game, Lineup, PositionRating, Team, Play from in_game.gameplay_queries import get_and_cache_position, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_last_team_play, get_one_lineup, get_player_id_from_dict, get_player_name_from_dict, get_player_or_none, get_sorted_lineups, get_team_or_none, get_players_last_pa, post_game_rewards from utilities.buttons import ButtonOptions, Confirm, ask_confirm from utilities.dropdown import DropdownOptions, DropdownView, SelectViewDefense @@ -33,6 +33,196 @@ AT_BASE = { } +async def get_scorebug_embed(session: Session, this_game: Game, full_length: bool = True, classic: bool = True) -> discord.Embed: + gt_string = ' - Unlimited' + if this_game.game_type == 'minor-league': + gt_string = ' - Minor League' + elif this_game.game_type == 'major-league': + gt_string = ' - Major League' + elif this_game.game_type == 'hall-of-fame': + gt_string = ' - Hall of Fame' + elif 'gauntlet' in this_game.game_type: + gt_string = ' - Gauntlet' + elif 'flashback' in this_game.game_type: + gt_string = ' - Flashback' + elif 'exhibition' in this_game.game_type: + gt_string = ' - Exhibition' + logger.info(f'gameplay_models - Game.get_scorebug_embed - this_game: {this_game} / gt_string: {gt_string}') + + embed = discord.Embed( + title=f'{this_game.away_team.sname} @ {this_game.home_team.sname}{gt_string}', + color=int(SBA_COLOR, 16) + ) + + curr_play = this_game.current_play_or_none(session) + + if curr_play is None: + try: + curr_play = this_game.initialize_play(session) + except LineupsMissingException as e: + logger.debug(f'gameplay_models - Game.get_scorebug_embed - Could not initialize play') + + if curr_play is not None: + embed.add_field( + name='Game State', + value=curr_play.scorebug_ascii, + inline=False + ) + + def steal_string(batting_card: BattingCard) -> str: + steal_string = '-/- (---)' + if batting_card.steal_jump > 0: + jump_chances = round(batting_card.steal_jump * 36) + + if jump_chances == 6: + good_jump = 7 + elif jump_chances == 5: + good_jump = 6 + elif jump_chances == 4: + good_jump = 5 + elif jump_chances == 3: + good_jump = 4 + elif jump_chances == 2: + good_jump = 3 + elif jump_chances == 1: + good_jump = 2 + elif jump_chances == 7: + good_jump = '4,5' + elif jump_chances == 8: + good_jump = '4,6' + elif jump_chances == 9: + good_jump = '3-5' + elif jump_chances == 10: + good_jump = '2-5' + elif jump_chances == 11: + good_jump = '6,7' + elif jump_chances == 12: + good_jump = '4-6' + elif jump_chances == 13: + good_jump = '2,4-6' + elif jump_chances == 14: + good_jump = '3-6' + elif jump_chances == 15: + good_jump = '2-6' + elif jump_chances == 16: + good_jump = '2,5-6' + elif jump_chances == 17: + good_jump = '3,5-6' + elif jump_chances == 18: + good_jump = '4-6' + elif jump_chances == 19: + good_jump = '2,4-7' + elif jump_chances == 20: + good_jump = '3-7' + elif jump_chances == 21: + good_jump = '2-7' + elif jump_chances == 22: + good_jump = '2-7,12' + elif jump_chances == 23: + good_jump = '2-7,11' + elif jump_chances == 24: + good_jump = '2,4-8' + elif jump_chances == 25: + good_jump = '3-8' + elif jump_chances == 26: + good_jump = '2-8' + elif jump_chances == 27: + good_jump = '2-8,12' + elif jump_chances == 28: + good_jump = '2-8,11' + elif jump_chances == 29: + good_jump = '3-9' + elif jump_chances == 30: + good_jump = '2-9' + elif jump_chances == 31: + good_jump = '2-9,12' + elif jump_chances == 32: + good_jump = '2-9,11' + elif jump_chances == 33: + good_jump = '2-10' + elif jump_chances == 34: + good_jump = '3-11' + elif jump_chances == 35: + good_jump = '2-11' + else: + good_jump = '2-12' + steal_string = f'{"*" if batting_card.steal_auto else ""}{good_jump}/- ({batting_card.steal_high}-{batting_card.steal_low})' + return steal_string + + baserunner_string = '' + if curr_play.on_first is not None: + runcard = curr_play.on_first.card.batterscouting.battingcard + baserunner_string += f'On First: {curr_play.on_first.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}\n' + if curr_play.on_second is not None: + runcard = curr_play.on_second.card.batterscouting.battingcard + baserunner_string += f'On Second: {curr_play.on_second.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}\n' + if curr_play.on_third is not None: + runcard = curr_play.on_third.card.batterscouting.battingcard + baserunner_string += f'On Third: {curr_play.on_third.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}\n' + logger.info(f'gameplay_models - Game.get_scorebug_embed - baserunner_string: {baserunner_string}') + + pit_string = f'{curr_play.pitcher.player.name_card_link('pitching')}' + bat_string = f'{curr_play.batter.player.name_card_link('batting')}' + if len(baserunner_string) > 0: + pitchingcard = curr_play.pitcher.card.pitcherscouting.pitchingcard + pit_string += f'\nHold: {pitchingcard.hold}, WP: {pitchingcard.wild_pitch}, Bk: {pitchingcard.balk}' + + # battingcard = curr_play.batter.card.batterscouting.battingcard + # bat_string += f'\nBunt: {battingcard.bunting}, HnR: {battingcard.hit_and_run}' + + embed.add_field( + name='Pitcher', + value=pit_string + ) + embed.add_field( + name='Batter', + value=bat_string + ) + embed.set_image(url=curr_play.batter.player.batter_card_url) + + if len(baserunner_string) > 0: + embed.add_field(name=' ', value=' ', inline=False) + embed.add_field(name='Baserunners', value=baserunner_string) + + c_query = session.exec(select(PositionRating).where(PositionRating.player_id == curr_play.catcher.card.player.id, PositionRating.position == 'C', PositionRating.variant == curr_play.catcher.card.variant)).all() + if len(c_query) > 0: + catcher_rating = c_query[0] + else: + log_exception(PositionNotFoundException, f'No catcher rating found for {curr_play.catcher.card.player.name}') + + cat_string = f'{curr_play.catcher.player.name_card_link('batter')}\nArm: {catcher_rating.arm}' + embed.add_field(name='Catcher', value=cat_string) + + ai_note = curr_play.ai_note + logger.info(f'gameplay_models - Game.get_scorebug_embed - ai_note: {ai_note}') + if len(ai_note) > 0: + gm_name = this_game.home_team.gmname if this_game.ai_team == 'home' else this_game.away_team.gmname + embed.add_field(name=f'{gm_name} will...', value=ai_note, inline=False) + else: + embed.add_field(name=' ', value=' ', inline=False) + + if full_length: + embed.add_field( + name=f'{this_game.away_team.abbrev} Lineup', + value=this_game.team_lineup(session, this_game.away_team) + ) + embed.add_field( + name=f'{this_game.home_team.abbrev} Lineup', + value=this_game.team_lineup(session, this_game.home_team) + ) + else: + embed.add_field( + name=f'{this_game.away_team.abbrev} Lineup', + value=this_game.team_lineup(session, this_game.away_team) + ) + embed.add_field( + name=f'{this_game.home_team.abbrev} Lineup', + value=this_game.team_lineup(session, this_game.home_team) + ) + + return embed + + def get_obc(on_first = None, on_second = None, on_third = None) -> int: if on_third is not None: if on_second is not None: @@ -1193,6 +1383,46 @@ async def bunts(session: Session, interaction: discord.Interaction, this_play: P return this_play +async def chaos(session: Session, interaction: discord.Interaction, this_play: Play, chaos_type: Literal['wild-pitch', 'passed-ball', 'balk', 'pickoff']): + """ + Commits this_play + """ + this_play.pa, this_play.ab = 0, 0 + + if chaos_type == 'wild-pitch': + this_play = advance_runners(session, this_play, 1) + this_play.rbi = 0 + this_play.wild_pitch = 1 + + elif chaos_type == 'passed-ball': + this_play = advance_runners(session, this_play, 1) + this_play.rbi = 0 + this_play.passed_ball = 1 + + elif chaos_type == 'balk': + this_play = advance_runners(session, this_play, 1) + this_play.rbi = 0 + this_play.balk = 1 + + elif chaos_type == 'pickoff': + this_play = advance_runners(session, this_play, 0) + this_play.pick_off = 1 + this_play.outs = 1 + + if this_play.on_third: + this_play.on_third_final = None + elif this_play.on_second: + this_play.on_second_final = None + elif this_play.on_first: + this_play.on_first_final = None + + session.add(this_play) + session.commit() + + session.refresh(this_play) + return this_play + + def activate_last_play(session: Session, this_game: Game) -> Play: p_query = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(1)).all() @@ -1596,3 +1826,29 @@ async def complete_game(session: Session, interaction: discord.Interaction, this session.commit() logger.info(f'Just ended game {game_id}') + + +async def update_game_settings(session: Session, interaction: discord.Interaction, this_game: Game, roll_buttons: bool = None, auto_roll: bool = None) -> discord.Embed: + if roll_buttons is not None: + this_game.roll_buttons = roll_buttons + if auto_roll is not None: + this_game.auto_roll = auto_roll + + session.add(this_game) + session.commit() + session.refresh(this_game) + + this_team = this_game.away_team if this_game.away_team.gmid == interaction.user.id else this_game.home_team + embed = this_team.embed + + embed.title = f'Game Settings - {this_team.lname}' + embed.add_field( + name='Roll Buttons', + value=f'{"ON" if this_game.roll_buttons else "OFF"}' + ) + embed.add_field( + name='Auto Roll', + value=f'{"ON" if this_game.auto_roll else "OFF"}' + ) + + return embed diff --git a/dice.py b/dice.py index 08da7a7..f4ff678 100644 --- a/dice.py +++ b/dice.py @@ -1,13 +1,33 @@ +import logging import discord import random +import pydantic + from helpers import INFIELD_X_CHART, OUTFIELD_X_CHART +from in_game.gameplay_models import Game, Team + +logger = logging.getLogger('discord_app') -def get_dice_embed(team: dict = None, embed_title: str = None): +class DiceRoll(pydantic.BaseModel): + model_config = pydantic.ConfigDict(arbitrary_types_allowed=True) + roll_message: str | None = None + embeds: list[discord.Embed] | None = None + + +class AbRoll(DiceRoll): + is_chaos: bool = False + d_six_one: int | None = None + d_six_two: int | None = None + d_six_three: int | None = None + d_twenty: int | None = None + + +def get_dice_embed(team: Team = None, embed_title: str = None): if team: embed = discord.Embed( - color=int(team["dice_color"], 16) if 'dice_color' in team else int(team["color"], 16) + color=int(team.color, 16) ) else: embed = discord.Embed( @@ -20,7 +40,7 @@ def get_dice_embed(team: dict = None, embed_title: str = None): return embed -def sa_fielding_roll(pos_code: str, team: dict) -> [discord.Embed]: +def sa_fielding_roll(pos_code: str, team: dict) -> list[discord.Embed]: """ Make a Super Advanced fielding check. """ @@ -622,40 +642,50 @@ def sa_fielding_roll(pos_code: str, team: dict) -> [discord.Embed]: '#heading=h.fpjqmiv10r8l' # Build range note - if d_twenty <= 2: + if d_twenty == 1: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - 'G3 ------SI1------\n' \ + 'G3# ------SI1------\n' \ '```\n' - elif d_twenty == 3: + elif d_twenty == 2: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '--G3--- ----SI1----\n' \ + 'G2# ------SI1------\n' \ '```\n' - elif d_twenty == 4: + elif d_twenty <= 4: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '----G3----- --SI1--\n' \ + 'G2# G3# ----SI1----\n' \ '```\n' - elif d_twenty <= 6: + elif d_twenty == 5: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '------G3------- SI1\n' \ + 'G2 --G3#-- --SI1--\n' \ '```\n' - elif d_twenty == 7: + elif d_twenty == 6: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '--------G3---------\n' \ + 'G1 G2# G3# --SI1--\n' \ '```\n' - elif d_twenty <= 9: + elif d_twenty <= 8: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - 'G2 ------G3-------\n' \ + 'G1 G2 --G3#-- SI1\n' \ + '```\n' + elif d_twenty == 9: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2 G3 --G3#--\n' \ + '```\n' + elif d_twenty == 10: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 --G3#--\n' \ '```\n' elif d_twenty <= 12: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - 'G1 G2 ----G3-----\n' \ + '--G1--- G2 G3 G3#\n' \ '```\n' elif d_twenty == 13: range_note = '```\n' \ @@ -670,12 +700,12 @@ def sa_fielding_roll(pos_code: str, team: dict) -> [discord.Embed]: elif d_twenty <= 16: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '--G1--- ----G2-----\n' \ + '----G1----- G2 G3\n' \ '```\n' elif d_twenty <= 18: range_note = '```\n' \ ' 1 | 2 | 3 | 4 | 5\n' \ - '----G1----- --G2---\n' \ + '------G1------- G3\n' \ '```\n' elif d_twenty == 19: range_note = '```\n' \ @@ -791,3 +821,99 @@ def frame_plate_check(team: dict, game_id: int): roll_embed.set_footer(text="This result will be logged automatically") return {'embed': roll_embed, 'is_walk': d_twenty <= this_ump['walk_d20']} + + +def ab_roll(this_team: Team, this_game: Game, allow_chaos: bool = True) -> AbRoll: + """ + Make an AB roll + """ + d_twenty = random.randint(1, 20) + d_twenty_two = random.randint(1, 20) + flag = None + + if allow_chaos: + if d_twenty == 1: + flag = 'wild pitch' + elif d_twenty == 2: + if random.randint(1, 2) == 1: + flag = 'balk' + else: + flag = 'passed ball' + + if flag: + roll_message = f'```md\nCheck {flag}```\n' \ + f'{flag.title()} roll```md\n# {d_twenty_two}\nDetails: [1d20 ({d_twenty_two})]```\n' + embed = get_dice_embed(this_team, f'Chaos roll for the {this_team.sname}', roll_message) + embed.set_footer( + text='If the chaos roll fails, ignore future chaos until a new batter comes to the plate.' + ) + # return {'is_chaos': True, 'embeds': [embed]} + return AbRoll( + roll_message=roll_message, + is_chaos=True, + embeds=[embed] + ) + + logger.info(f'Pre-AB roll') + this_roll = AbRoll( + d_six_one=random.randint(1, 6), + d_six_two=random.randint(1, 6), + d_six_three=random.randint(1, 6), + d_twenty=random.randint(1, 20) + ) + logger.info(f'AB roll base: {this_roll}') + + this_roll.roll_message = f'```md\n# {this_roll.d_six_one},{this_roll.d_six_two + this_roll.d_six_three},{this_roll.d_twenty}\nDetails:[1d6;2d6;1d20 ({this_roll.d_six_one} - {this_roll.d_six_two} {this_roll.d_six_three} - {this_roll.d_twenty})]```' + + logger.info(f'AB roll with message: {this_roll}') + + embed = get_dice_embed(this_team) + embed.add_field( + name=f'At bat roll for the {this_team.sname}', + value=this_roll.roll_message + ) + + this_roll.embeds = [embed] + + # if d_six_one == 6 and d_six_two + d_six_three > 6: + # roll_message += f'\n**Check injury for pitcher injury rating {13 - d_six_two - d_six_three}**\n' \ + # f'Oops! All injuries!' + + + logger.info(f'Game {this_game.id} | Team {this_team.id} ({this_team.abbrev}): {this_roll.roll_message}') + return this_roll + + +def jump_roll(this_team: Team, this_game: Game) -> list[discord.Embed]: + """ + Check for a baserunner's jump before stealing + """ + d_six_one = random.randint(1, 6) + d_six_two = random.randint(1, 6) + d_twenty = random.randint(1, 20) + d_twenty_two = random.randint(1, 20) + flag = None + + if d_twenty == 1: + flag = 'pickoff' + elif d_twenty == 2: + flag = 'balk' + + if not flag: + roll_message = f'```md\n# {d_six_one + d_six_two}\n'\ + f'Details:[2d6 ({d_six_one} {d_six_two})]```' + else: + roll_message = f'```md\nCheck {flag}```\n' \ + f'{flag.title()} roll```md\n# {d_twenty_two}\nDetails: [1d20 ({d_twenty_two})]```' + + embed = get_dice_embed(this_team) + embed.add_field( + name=f'Jump check for the {this_team.sname}', + value=roll_message + ) + + + logger.info(f'Game {this_game.id} | Team {this_team.id} ({this_team.abbrev}): {roll_message}') + return [embed] + + diff --git a/in_game/gameplay_models.py b/in_game/gameplay_models.py index 90bc639..995f820 100644 --- a/in_game/gameplay_models.py +++ b/in_game/gameplay_models.py @@ -106,6 +106,8 @@ class Game(SQLModel, table=True): first_message: str | None = Field(default=None) ai_team: str | None = Field(default=None) game_type: str + roll_buttons: bool | None = Field(default=False) + auto_roll: bool | None = Field(default=True) cardset_links: list[GameCardsetLink] = Relationship(back_populates='game', cascade_delete=True) away_team: Team = Relationship( @@ -151,94 +153,191 @@ class Game(SQLModel, table=True): else: return None - def get_scorebug_embed(self, session: Session, full_length: bool = True, classic: bool = True) -> discord.Embed: - gt_string = ' - Unlimited' - if self.game_type == 'minor-league': - gt_string = ' - Minor League' - elif self.game_type == 'major-league': - gt_string = ' - Major League' - elif self.game_type == 'hall-of-fame': - gt_string = ' - Hall of Fame' - elif 'gauntlet' in self.game_type: - gt_string = ' - Gauntlet' - elif 'flashback' in self.game_type: - gt_string = ' - Flashback' - elif 'exhibition' in self.game_type: - gt_string = ' - Exhibition' - logger.info(f'gameplay_models - Game.get_scorebug_embed - this_game: {self} / gt_string: {gt_string}') + # async def get_scorebug_embed(self, session: Session, full_length: bool = True, classic: bool = True) -> discord.Embed: + # gt_string = ' - Unlimited' + # if self.game_type == 'minor-league': + # gt_string = ' - Minor League' + # elif self.game_type == 'major-league': + # gt_string = ' - Major League' + # elif self.game_type == 'hall-of-fame': + # gt_string = ' - Hall of Fame' + # elif 'gauntlet' in self.game_type: + # gt_string = ' - Gauntlet' + # elif 'flashback' in self.game_type: + # gt_string = ' - Flashback' + # elif 'exhibition' in self.game_type: + # gt_string = ' - Exhibition' + # logger.info(f'gameplay_models - Game.get_scorebug_embed - this_game: {self} / gt_string: {gt_string}') - embed = discord.Embed( - title=f'{self.away_team.sname} @ {self.home_team.sname}{gt_string}', - color=int(SBA_COLOR, 16) - ) + # embed = discord.Embed( + # title=f'{self.away_team.sname} @ {self.home_team.sname}{gt_string}', + # color=int(SBA_COLOR, 16) + # ) - curr_play = self.current_play_or_none(session) + # curr_play = self.current_play_or_none(session) - if curr_play is None: - try: - curr_play = self.initialize_play(session) - except LineupsMissingException as e: - logger.debug(f'gameplay_models - Game.get_scorebug_embed - Could not initialize play') + # if curr_play is None: + # try: + # curr_play = self.initialize_play(session) + # except LineupsMissingException as e: + # logger.debug(f'gameplay_models - Game.get_scorebug_embed - Could not initialize play') - if curr_play is not None: - embed.add_field( - name='Game State', - value=curr_play.scorebug_ascii, - inline=False - ) + # if curr_play is not None: + # embed.add_field( + # name='Game State', + # value=curr_play.scorebug_ascii, + # inline=False + # ) - if classic: - embed.add_field( - name='Pitcher', - value=curr_play.pitcher.player.name_card_link('pitching') - ) - embed.add_field( - name='Batter', - value=curr_play.batter.player.name_card_link('batting') - ) + # def steal_string(batting_card: BattingCard) -> str: + # steal_string = '-/- (---)' + # if batting_card.steal_jump > 0: + # jump_chances = round(batting_card.steal_jump * 36) - baserunner_string = '' - if curr_play.on_first is not None: - baserunner_string += f'On First: {curr_play.on_first.player.name_card_link('batting')}\n' - if curr_play.on_second is not None: - baserunner_string += f'On Second: {curr_play.on_second.player.name_card_link('batting')}\n' - if curr_play.on_third is not None: - baserunner_string += f'On Third: {curr_play.on_third.player.name_card_link('batting')}' - logger.info(f'gameplay_models - Game.get_scorebug_embed - baserunner_string: {baserunner_string}') + # if jump_chances == 6: + # good_jump = 7 + # elif jump_chances == 5: + # good_jump = 6 + # elif jump_chances == 4: + # good_jump = 5 + # elif jump_chances == 3: + # good_jump = 4 + # elif jump_chances == 2: + # good_jump = 3 + # elif jump_chances == 1: + # good_jump = 2 + # elif jump_chances == 7: + # good_jump = '4,5' + # elif jump_chances == 8: + # good_jump = '4,6' + # elif jump_chances == 9: + # good_jump = '3-5' + # elif jump_chances == 10: + # good_jump = '2-5' + # elif jump_chances == 11: + # good_jump = '6,7' + # elif jump_chances == 12: + # good_jump = '4-6' + # elif jump_chances == 13: + # good_jump = '2,4-6' + # elif jump_chances == 14: + # good_jump = '3-6' + # elif jump_chances == 15: + # good_jump = '2-6' + # elif jump_chances == 16: + # good_jump = '2,5-6' + # elif jump_chances == 17: + # good_jump = '3,5-6' + # elif jump_chances == 18: + # good_jump = '4-6' + # elif jump_chances == 19: + # good_jump = '2,4-7' + # elif jump_chances == 20: + # good_jump = '3-7' + # elif jump_chances == 21: + # good_jump = '2-7' + # elif jump_chances == 22: + # good_jump = '2-7,12' + # elif jump_chances == 23: + # good_jump = '2-7,11' + # elif jump_chances == 24: + # good_jump = '2,4-8' + # elif jump_chances == 25: + # good_jump = '3-8' + # elif jump_chances == 26: + # good_jump = '2-8' + # elif jump_chances == 27: + # good_jump = '2-8,12' + # elif jump_chances == 28: + # good_jump = '2-8,11' + # elif jump_chances == 29: + # good_jump = '3-9' + # elif jump_chances == 30: + # good_jump = '2-9' + # elif jump_chances == 31: + # good_jump = '2-9,12' + # elif jump_chances == 32: + # good_jump = '2-9,11' + # elif jump_chances == 33: + # good_jump = '2-10' + # elif jump_chances == 34: + # good_jump = '3-11' + # elif jump_chances == 35: + # good_jump = '2-11' + # else: + # good_jump = '2-12' + # steal_string = f'{"*" if batting_card.steal_auto else ""}{good_jump}/- ({batting_card.steal_high}-{batting_card.steal_low})' + # return steal_string + + # baserunner_string = '' + # if curr_play.on_first is not None: + # runcard = curr_play.on_first.card.batterscouting.battingcard + # baserunner_string += f'On First: {curr_play.on_first.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}' + # if curr_play.on_second is not None: + # baserunner_string += f'On Second: {curr_play.on_second.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}' + # if curr_play.on_third is not None: + # baserunner_string += f'On Third: {curr_play.on_third.player.name_card_link('batting')}\nSteal: {steal_string(runcard)}, Run: {runcard.running}' + # logger.info(f'gameplay_models - Game.get_scorebug_embed - baserunner_string: {baserunner_string}') - 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=curr_play.catcher.player.name_card_link('batter')) + # pit_string = f'{curr_play.pitcher.player.name_card_link('pitching')}' + # bat_string = f'{curr_play.batter.player.name_card_link('batting')}' + # if len(baserunner_string) > 0: + # pitchingcard = curr_play.pitcher.card.pitcherscouting.pitchingcard + # pit_string += f'\nHold: {pitchingcard.hold}, WP: {pitchingcard.wild_pitch}, Bk: {pitchingcard.balk}' + + # # battingcard = curr_play.batter.card.batterscouting.battingcard + # # bat_string += f'\nBunt: {battingcard.bunting}, HnR: {battingcard.hit_and_run}' - ai_note = curr_play.ai_note - logger.info(f'gameplay_models - Game.get_scorebug_embed - ai_note: {ai_note}') - if len(ai_note) > 0: - gm_name = self.home_team.gmname if self.ai_team == 'home' else self.away_team.gmname - embed.add_field(name=f'{gm_name} will...', value=ai_note, inline=False) - else: - embed.add_field(name=' ', value=' ', inline=False) - - if full_length: - embed.add_field( - name=f'{self.away_team.abbrev} Lineup', - value=self.team_lineup(session, self.away_team) - ) - embed.add_field( - name=f'{self.home_team.abbrev} Lineup', - value=self.team_lineup(session, self.home_team) - ) - else: - embed.add_field( - name=f'{self.away_team.abbrev} Lineup', - value=self.team_lineup(session, self.away_team) - ) - embed.add_field( - name=f'{self.home_team.abbrev} Lineup', - value=self.team_lineup(session, self.home_team) - ) + # embed.add_field( + # name='Pitcher', + # value=pit_string + # ) + # embed.add_field( + # name='Batter', + # value=bat_string + # ) - return embed + # if len(baserunner_string) > 0: + # embed.add_field(name=' ', value=' ', inline=False) + # embed.add_field(name='Baserunners', value=baserunner_string) + + # c_query = session.exec(select(PositionRating).where(PositionRating.player_id == curr_play.catcher.card.player.id, PositionRating.position == 'C', PositionRating.variant == curr_play.catcher.card.variant)).all() + # if len(c_query) > 0: + # catcher_rating = c_query[0] + # else: + # log_exception(PositionNotFoundException, f'No catcher rating found for {curr_play.catcher.card.player.name}') + + # cat_string = f'{curr_play.catcher.player.name_card_link('batter')}\nArm: {catcher_rating.arm}' + # embed.add_field(name='Catcher', value=cat_string) + + # ai_note = curr_play.ai_note + # logger.info(f'gameplay_models - Game.get_scorebug_embed - ai_note: {ai_note}') + # if len(ai_note) > 0: + # gm_name = self.home_team.gmname if self.ai_team == 'home' else self.away_team.gmname + # embed.add_field(name=f'{gm_name} will...', value=ai_note, inline=False) + # else: + # embed.add_field(name=' ', value=' ', inline=False) + + # if full_length: + # embed.add_field( + # name=f'{self.away_team.abbrev} Lineup', + # value=self.team_lineup(session, self.away_team) + # ) + # embed.add_field( + # name=f'{self.home_team.abbrev} Lineup', + # value=self.team_lineup(session, self.home_team) + # ) + # else: + # embed.add_field( + # name=f'{self.away_team.abbrev} Lineup', + # value=self.team_lineup(session, self.away_team) + # ) + # embed.add_field( + # name=f'{self.home_team.abbrev} Lineup', + # value=self.team_lineup(session, self.home_team) + # ) + + # return embed def initialize_play(self, session: Session): """ @@ -655,6 +754,24 @@ class Player(PlayerBase, table=True): def name_with_desc(self): return f'{self.description} {self.name}' + @property + def batter_card_url(self): + if 'batting' in self.image: + return self.image + elif 'batting' in self.image2: + return self.image2 + else: + return None + + @property + def pitcher_card_url(self): + if 'pitching' in self.image: + return self.image + elif 'pitching' in self.image2: + return self.image2 + else: + return None + def player_description(player: Player = None, player_dict: dict = None) -> str: if player is None and player_dict is None: @@ -1110,7 +1227,14 @@ class Play(PlayBase, table=True): @property def could_walkoff(self) -> bool: - return False + if self.inning_half == 'bot' and self.on_third is not None: + runs_needed = self.away_score - self.home_score + 1 + + if runs_needed == 2 or (self.home_score - self.away_score == 9): + return True + + else: + return False """ diff --git a/tests/gameplay_models/test_batterscouting_model.py b/tests/gameplay_models/test_batterscouting_model.py index 788b3b1..21ff44b 100644 --- a/tests/gameplay_models/test_batterscouting_model.py +++ b/tests/gameplay_models/test_batterscouting_model.py @@ -204,23 +204,23 @@ sample_ratings_query = { } -async def test_create_scouting(session: Session): - this_card = await get_card_or_none(session, card_id=1405) +# async def test_create_scouting(session: Session): +# this_card = await get_card_or_none(session, card_id=1405) - assert this_card.player.id == 395 - assert this_card.team.id == 31 - assert this_card.batterscouting.battingcard_id == sample_ratings_query["ratings"][0]['battingcard']['id'] +# assert this_card.player.id == 395 +# assert this_card.team.id == 31 +# assert this_card.batterscouting.battingcard_id == sample_ratings_query["ratings"][0]['battingcard']['id'] - # this_scouting = await get_batter_scouting_or_none(session, this_card) +# # this_scouting = await get_batter_scouting_or_none(session, this_card) - # assert this_scouting.battingcard_id == sample_ratings_query["ratings"][0]['battingcard']['id'] +# # assert this_scouting.battingcard_id == sample_ratings_query["ratings"][0]['battingcard']['id'] - # this_card = await get_card_or_none(session, card_id=1406) +# # this_card = await get_card_or_none(session, card_id=1406) - # assert this_card.player.id == 161 - # assert this_card.team.id == 31 +# # assert this_card.player.id == 161 +# # assert this_card.team.id == 31 - # this_scouting = await get_pitcher_scouting_or_none(session, this_card) +# # this_scouting = await get_pitcher_scouting_or_none(session, this_card) - # assert this_scouting.pitchingcard_id == 4294 +# # assert this_scouting.pitchingcard_id == 4294 diff --git a/tests/gameplay_models/test_card_model.py b/tests/gameplay_models/test_card_model.py index bf87441..b9a4a62 100644 --- a/tests/gameplay_models/test_card_model.py +++ b/tests/gameplay_models/test_card_model.py @@ -42,21 +42,21 @@ async def test_get_or_create_ai_card(session: Session): assert new_card_2.id == 42 -async def test_get_card_or_none(session: Session): - card_1 = session.get(Card, 1) - new_card_1 = await get_card_or_none(session, card_id=card_1.id) +# async def test_get_card_or_none(session: Session): +# card_1 = session.get(Card, 1) +# new_card_1 = await get_card_or_none(session, card_id=card_1.id) - assert card_1.created == new_card_1.created +# assert card_1.created == new_card_1.created - assert session.get(Player, 538) is None - assert session.get(Team, 55) is None +# assert session.get(Player, 538) is None +# assert session.get(Team, 55) is None - new_card_2 = await get_card_or_none(session, card_id=55555) - print(f'new_card_2: {new_card_2}\nplayer: {new_card_2.player}\nteam: {new_card_2.team}') +# new_card_2 = await get_card_or_none(session, card_id=55555) +# print(f'new_card_2: {new_card_2}\nplayer: {new_card_2.player}\nteam: {new_card_2.team}') - assert new_card_2 is not None - assert new_card_2.player_id == 538 - assert new_card_2.team_id == 55 - assert session.get(Player, 538) is not None - assert session.get(Team, 55) is not None +# assert new_card_2 is not None +# assert new_card_2.player_id == 538 +# assert new_card_2.team_id == 55 +# assert session.get(Player, 538) is not None +# assert session.get(Team, 55) is not None diff --git a/tests/gameplay_models/test_game_model.py b/tests/gameplay_models/test_game_model.py index c25377e..2c8752c 100644 --- a/tests/gameplay_models/test_game_model.py +++ b/tests/gameplay_models/test_game_model.py @@ -3,7 +3,7 @@ from sqlalchemy import delete as sadelete from sqlalchemy.sql.functions import sum, count from sqlmodel import Session, delete, func -from command_logic.logic_gameplay import complete_play, homeruns, is_game_over, singles, strikeouts, undo_play +from command_logic.logic_gameplay import complete_play, get_scorebug_embed, homeruns, is_game_over, singles, strikeouts, undo_play from in_game.gameplay_models import Game, Lineup, GameCardsetLink, Play, Team, select from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team, get_db_ready_decisions from tests.factory import session_fixture @@ -109,15 +109,17 @@ def test_delete_game(session: Session): assert len(bad_links) == 0 -def test_get_scorebug(session: Session): +async def test_get_scorebug(session: Session): game_1 = session.get(Game, 1) - scorebug = game_1.get_scorebug_embed(session) + # scorebug = game_1.get_scorebug_embed(session) + scorebug = await get_scorebug_embed(session, game_1) assert scorebug.title == 'CornBelters @ Black Bears - Minor League' assert scorebug.color.value == int('a6ce39', 16) game_3 = session.get(Game, 3) - scorebug = game_3.get_scorebug_embed(session) + # scorebug = game_3.get_scorebug_embed(session) + scorebug = await get_scorebug_embed(session, game_3) assert '0 Outs' in scorebug.fields[0].value diff --git a/tests/other/test_dice.py b/tests/other/test_dice.py new file mode 100644 index 0000000..2bc451d --- /dev/null +++ b/tests/other/test_dice.py @@ -0,0 +1,19 @@ +import pytest +from sqlmodel import Session, select, func + +from dice import ab_roll +from in_game.gameplay_models import Game +from tests.factory import session_fixture + + +def test_ab_roll(session: Session): + game_1 = session.get(Game, 1) + play_2 = game_1.initialize_play(session) + + this_roll = ab_roll(game_1.away_team, game_1, allow_chaos=False) + + assert this_roll.d_six_one is not None + assert this_roll.d_six_two is not None + assert this_roll.d_six_three is not None + assert this_roll.d_twenty is not None + assert this_roll.roll_message is not None diff --git a/utilities/buttons.py b/utilities/buttons.py index 13fac8b..eb959d0 100644 --- a/utilities/buttons.py +++ b/utilities/buttons.py @@ -1,5 +1,12 @@ +import logging import discord -from typing import Literal +from typing import Coroutine, Literal + +from dice import ab_roll, jump_roll +from in_game.gameplay_models import Game, Play, Team + + +logger = logging.getLogger('discord_app') class Confirm(discord.ui.View): def __init__(self, responders: list, timeout: float = 300.0, label_type: Literal['yes', 'confirm'] = 'confirm'): @@ -18,7 +25,11 @@ class Confirm(discord.ui.View): @discord.ui.button(label='Confirm', style=discord.ButtonStyle.green) async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = True self.clear_items() @@ -28,7 +39,11 @@ class Confirm(discord.ui.View): @discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey) async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = False self.clear_items() @@ -68,7 +83,11 @@ class ButtonOptions(discord.ui.View): @discord.ui.button(label='Option 1', style=discord.ButtonStyle.primary) async def option1(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = self.options[0] self.clear_items() @@ -77,7 +96,11 @@ class ButtonOptions(discord.ui.View): @discord.ui.button(label='Option 2', style=discord.ButtonStyle.primary) async def option2(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = self.options[1] self.clear_items() @@ -86,7 +109,11 @@ class ButtonOptions(discord.ui.View): @discord.ui.button(label='Option 3', style=discord.ButtonStyle.primary) async def option3(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = self.options[2] self.clear_items() @@ -95,7 +122,11 @@ class ButtonOptions(discord.ui.View): @discord.ui.button(label='Option 4', style=discord.ButtonStyle.primary) async def option4(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = self.options[3] self.clear_items() @@ -104,7 +135,11 @@ class ButtonOptions(discord.ui.View): @discord.ui.button(label='Option 5', style=discord.ButtonStyle.primary) async def option5(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: - return + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=10.0 + ) self.value = self.options[4] self.clear_items() @@ -140,3 +175,61 @@ async def ask_confirm(interaction: discord.Interaction, question: str, label_typ else: await question.edit(content=question, view=None) return False + + +class ScorebugButtons(discord.ui.View): + def __init__(self, play: Play, timeout: float = 30): + super().__init__(timeout=timeout) + self.value = None + self.batting_team = play.batter.team + self.pitching_team = play.pitcher.team + self.team = play.batter.team + self.play = play + self.had_chaos = False + + if play.on_base_code == 0: + self.remove_item(self.button_jump) + + async def interaction_check(self, interaction: discord.Interaction[discord.Client]) -> bool: + logger.info(f'user id: {interaction.user.id} / batting_team: {self.batting_team}') + if interaction.user.id == self.batting_team.gmid: + logger.info(f'User {interaction.user.id} rolling in Game {self.play.game.id}') + return True + elif self.batting_team.is_ai and interaction.user.id == self.pitching_team.gmid: + logger.info(f'User {interaction.user.id} rolling for AI in Game {self.play.game.id}') + return True + + logger.info(f'User {interaction.user.id} rejected in Game {self.play.game.id}') + await interaction.response.send_message( + content='Get out of here', + ephemeral=True, + delete_after=5.0 + ) + return False + + # async def on_timeout(self) -> Coroutine[Any, Any, None]: + # await self.interaction + + @discord.ui.button(label='Roll AB', style=discord.ButtonStyle.primary) + async def button_ab(self, interaction: discord.Interaction, button: discord.ui.Button): + logger.info(f'User {interaction.user.id} rolling AB in Game {self.play.game.id}') + + this_roll = ab_roll(self.team, self.play.game, allow_chaos=not self.had_chaos) + if this_roll.is_chaos: + self.had_chaos = True + else: + button.disabled = True + + await interaction.channel.send(content=None, embeds=this_roll.embeds) + await interaction.response.edit_message(view=self) + + @discord.ui.button(label='Check Jump', style=discord.ButtonStyle.secondary) + async def button_jump(self, interaction: discord.Interaction, button: discord.ui.Button): + logger.info(f'User {interaction.user.id} rolling jump in Game {self.play.game.id}') + + this_roll = jump_roll(self.team, self.play.game) + button.disabled = True + + await interaction.channel.send(content=None, embeds=this_roll) + await interaction.response.edit_message(view=self) +