Batter subs plus cleanup
This commit is contained in:
parent
f9ced5cb9e
commit
7f6472bbc6
184
cogs/gameplay.py
184
cogs/gameplay.py
@ -11,9 +11,10 @@ import pygsheets
|
||||
from sqlmodel import or_
|
||||
|
||||
from api_calls import db_get
|
||||
from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, frame_checks, get_full_roster_from_sheets, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, groundballs, hit_by_pitch, homeruns, is_game_over, lineouts, manual_end_game, popouts, read_lineup, show_defense_cards, singles, starting_pitcher_dropdown_view, steals, strikeouts, triples, undo_play, update_game_settings, walks, xchecks
|
||||
from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, frame_checks, get_full_roster_from_sheets, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, groundballs, hit_by_pitch, homeruns, is_game_over, lineouts, manual_end_game, popouts, read_lineup, show_defense_cards, singles, starting_pitcher_dropdown_view, steals, strikeouts, sub_batter_dropdown_view, triples, undo_play, update_game_settings, walks, xchecks, activate_last_play
|
||||
from dice import ab_roll
|
||||
from exceptions import GameNotFoundException, GoogleSheetsException, TeamNotFoundException, PlayNotFoundException, GameException, log_exception
|
||||
import gauntlets
|
||||
from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, get_channel, team_role, user_has_role, random_gif, random_from_list
|
||||
|
||||
# from in_game import ai_manager
|
||||
@ -55,8 +56,16 @@ class Gameplay(commands.Cog):
|
||||
logger.error(msg=error, stack_info=True)
|
||||
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')
|
||||
async def post_play(self, session: Session, interaction: discord.Interaction, this_play: Play, buffer_message: str = None, full_length: bool = False):
|
||||
logger.info(f'post_play - Posting new play: {this_play}')
|
||||
|
||||
if this_play is None:
|
||||
logger.info(f'this_play is None, searching for game in channel {interaction.channel.id}')
|
||||
this_game = get_channel_game_or_none(session, interaction.channel.id)
|
||||
this_play = activate_last_play(session, this_game)
|
||||
if this_play is None:
|
||||
log_exception(PlayNotFoundException, f'Attempting to display gamestate, but cannot find current 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!')
|
||||
@ -83,39 +92,51 @@ class Gameplay(commands.Cog):
|
||||
await interaction.channel.send(content=f'I let Cal know his bot is stupid')
|
||||
|
||||
scorebug_buttons, this_ab_roll = None, None
|
||||
scorebug_embed = await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED)
|
||||
scorebug_embed = await get_scorebug_embed(session, this_play.game, full_length=full_length, classic=CLASSIC_EMBED)
|
||||
|
||||
if this_play.game.roll_buttons and interaction.user.id in [this_play.game.away_team.gmid, this_play.game.home_team.gmid]:
|
||||
logger.info(f'Including scorebug buttons')
|
||||
scorebug_buttons = ScorebugButtons(this_play, scorebug_embed)
|
||||
|
||||
if this_play.on_base_code == 0 and this_play.game.auto_roll and not this_play.batter.team.is_ai and not this_play.is_new_inning:
|
||||
logger.info(f'Rolling ab')
|
||||
this_ab_roll = ab_roll(this_play.batter.team, this_play.game, allow_chaos=False)
|
||||
scorebug_buttons = None
|
||||
|
||||
if this_ab_roll is not None and this_ab_roll.d_six_one > 3:
|
||||
logger.info(f'Setting embed image to pitcher')
|
||||
scorebug_embed.set_image(url=this_play.pitcher.player.pitcher_card_url)
|
||||
|
||||
if buffer_message is not None:
|
||||
logger.info(f'Posting buffered message')
|
||||
await interaction.edit_original_response(
|
||||
content=buffer_message
|
||||
)
|
||||
await interaction.channel.send(
|
||||
sb_message = await interaction.channel.send(
|
||||
content=None,
|
||||
embed=scorebug_embed,
|
||||
view=scorebug_buttons
|
||||
)
|
||||
else:
|
||||
await interaction.edit_original_response(
|
||||
logger.info(f'Posting unbuffered message')
|
||||
sb_message = await interaction.edit_original_response(
|
||||
content=None,
|
||||
embed=scorebug_embed,
|
||||
view=scorebug_buttons
|
||||
)
|
||||
|
||||
if this_ab_roll is not None:
|
||||
logger.info(f'Posting ab roll')
|
||||
await interaction.channel.send(
|
||||
content=None,
|
||||
embeds=this_ab_roll.embeds
|
||||
)
|
||||
|
||||
if scorebug_buttons is not None:
|
||||
logger.info(f'Posting scorebug buttons roll')
|
||||
await scorebug_buttons.wait()
|
||||
if not scorebug_buttons.value:
|
||||
await sb_message.edit(view=None)
|
||||
|
||||
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)
|
||||
@ -293,7 +314,7 @@ class Gameplay(commands.Cog):
|
||||
)
|
||||
|
||||
# Get pitchers from rosterlinks
|
||||
done = await get_full_roster_from_sheets(session, interaction, self.sheets, this_game, human_team, roster.value)
|
||||
done = await get_full_roster_from_sheets(session, interaction, self.sheets, this_game, human_team, int(roster.value))
|
||||
logger.info(f'done: {done}')
|
||||
if done:
|
||||
sp_view = starting_pitcher_dropdown_view(session, this_game, human_team)
|
||||
@ -303,7 +324,120 @@ class Gameplay(commands.Cog):
|
||||
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
|
||||
f'Go ahead and set lineups with the `/read-lineup` command!',
|
||||
embed=embed
|
||||
)
|
||||
)
|
||||
|
||||
@group_new_game.command(name='gauntlet', description='Start a new Gauntlet game against an AI')
|
||||
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
||||
async def new_game_gauntlet_command(self, interaction: discord.Interaction):
|
||||
await interaction.response.defer()
|
||||
|
||||
with Session(engine) as session:
|
||||
conflict = get_channel_game_or_none(session, interaction.channel_id)
|
||||
if conflict is not None:
|
||||
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
|
||||
|
||||
if interaction.channel.category is None or interaction.channel.category.name != PUBLIC_FIELDS_CATEGORY_NAME:
|
||||
await interaction.edit_original_response(
|
||||
content=f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything pops up?'
|
||||
)
|
||||
return
|
||||
|
||||
main_team = await get_team_or_none(
|
||||
session,
|
||||
gm_id=interaction.user.id
|
||||
)
|
||||
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
|
||||
|
||||
this_team = await get_team_or_none(
|
||||
session,
|
||||
team_abbrev=f'Gauntlet-{main_team.abbrev}'
|
||||
)
|
||||
if not this_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
|
||||
|
||||
e_query = await db_get('events', params=[('active', True)])
|
||||
if e_query['count'] == 0:
|
||||
await interaction.edit_original_response(
|
||||
content=f'Hm. It looks like there aren\'t any active gauntlets. What do we even pay Cal for?'
|
||||
)
|
||||
return
|
||||
|
||||
elif e_query['count'] == 1:
|
||||
this_event = e_query['events'][0]
|
||||
r_query = await db_get(
|
||||
'gauntletruns',
|
||||
params=[('team_id', this_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]
|
||||
|
||||
else:
|
||||
r_query = await db_get(
|
||||
'gauntletruns',
|
||||
params=[('team_id', this_team['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 {e_query["events"][0]["name"]}` and we can get you started in no time!'
|
||||
)
|
||||
return
|
||||
else:
|
||||
this_run = r_query['runs'][0]
|
||||
this_event = r_query['runs'][0]['gauntlet']
|
||||
|
||||
# If not new or after draft, create new AI game
|
||||
is_home = gauntlets.is_home_team(this_team, this_event, this_run)
|
||||
opponent = await gauntlets.get_opponent(this_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. Plz ping the shit out of Cal!'
|
||||
)
|
||||
return
|
||||
else:
|
||||
logger.info(f'opponent: {opponent}')
|
||||
|
||||
current = await db_get('current')
|
||||
game_code = gauntlets.get_game_code(this_team, this_event, this_run)
|
||||
|
||||
this_game = Game(
|
||||
away_team_id=opponent.id if is_home else this_team.id,
|
||||
home_team_id=this_team.id if is_home else opponent.id,
|
||||
channel_id=interaction.channel_id,
|
||||
season=current['season'],
|
||||
week=current['week'],
|
||||
first_message=None if interaction.message is None else interaction.message.channel.id,
|
||||
ai_team='away' if is_home else 'home',
|
||||
game_type=game_code
|
||||
)
|
||||
logger.info(
|
||||
f'Game {this_game.id} between {this_team.abbrev} and {opponent.abbrev} is posted!'
|
||||
)
|
||||
t_role = await team_role(interaction, main_team)
|
||||
|
||||
await interaction.edit_original_response(
|
||||
content=f'Creating this game for {t_role.mention}:\n{this_game}'
|
||||
)
|
||||
|
||||
|
||||
@commands.command(name='force-endgame', help='Mod: Force a game to end without stats')
|
||||
async def force_end_game_command(self, ctx: commands.Context):
|
||||
@ -332,7 +466,8 @@ class Gameplay(commands.Cog):
|
||||
|
||||
# if view.value:
|
||||
if nuke_game:
|
||||
session.delete(this_game)
|
||||
this_game.active = False
|
||||
session.add(this_game)
|
||||
session.commit()
|
||||
await ctx.channel.send(content=random_gif(random_from_list(['i killed it', 'deed is done', 'gone forever'])))
|
||||
else:
|
||||
@ -419,6 +554,23 @@ class Gameplay(commands.Cog):
|
||||
# await interaction.edit_original_response(content='Let\'s see, I didn\'t think this game was over...')
|
||||
await manual_end_game(session, interaction, this_game, current_play=this_play)
|
||||
|
||||
group_substitution = app_commands.Group(name='substitute', description='Make a substitution in active game')
|
||||
|
||||
@group_substitution.command(name='batter', description='Make a batter substitution')
|
||||
async def sub_batter_command(self, interaction: discord.Interaction, batting_order: Literal['this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9'] = 'this-spot'):
|
||||
with Session(engine) as session:
|
||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='substitute batter')
|
||||
|
||||
if batting_order == 'this-spot':
|
||||
this_order = this_play.batting_order
|
||||
else:
|
||||
this_order = int(batting_order)
|
||||
|
||||
logger.info(f'sub batter - this_play: {this_play}')
|
||||
bat_view = sub_batter_dropdown_view(session, this_game, owner_team, this_order)
|
||||
await interaction.edit_original_response(content=f'### {owner_team.lname} Substitution', view=bat_view)
|
||||
|
||||
|
||||
group_log = app_commands.Group(name='log', description='Log a play in this channel\'s game')
|
||||
|
||||
@group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c')
|
||||
@ -472,20 +624,6 @@ class Gameplay(commands.Cog):
|
||||
|
||||
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)
|
||||
|
||||
# if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped'):
|
||||
# await interaction.edit_original_response(content='Single logged')
|
||||
# await interaction.channel.send(
|
||||
# content=None,
|
||||
# embed=await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED)
|
||||
# )
|
||||
# else:
|
||||
# await interaction.edit_original_response(
|
||||
# content=None,
|
||||
# embed=await get_scorebug_embed(session, this_play.game, full_length=False, classic=CLASSIC_EMBED)
|
||||
# )
|
||||
|
||||
@group_log.command(name='double', description='Doubles: **, ***, uncapped')
|
||||
async def log_double(self, interaction: discord.Interaction, double_type: Literal['**', '***', 'uncapped']):
|
||||
with Session(engine) as session:
|
||||
|
||||
@ -15,10 +15,10 @@ from exceptions import *
|
||||
from helpers import DEFENSE_LITERAL, SBA_COLOR, get_channel
|
||||
from in_game.game_helpers import legal_check
|
||||
from in_game.gameplay_models import BattingCard, Game, Lineup, PositionRating, RosterLink, Team, Play
|
||||
from in_game.gameplay_queries import get_position, get_available_pitchers, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_game_lineups, 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 in_game.gameplay_queries import get_available_batters, get_position, get_available_pitchers, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_game_lineups, 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 in_game.managerai_responses import DefenseResponse
|
||||
from utilities.buttons import ButtonOptions, Confirm, ask_confirm
|
||||
from utilities.dropdown import DropdownView, SelectStartingPitcher, SelectViewDefense
|
||||
from utilities.dropdown import DropdownView, SelectBatterSub, SelectStartingPitcher, SelectViewDefense
|
||||
from utilities.embeds import image_embed
|
||||
from utilities.pages import Pagination
|
||||
|
||||
@ -51,7 +51,7 @@ async def get_scorebug_embed(session: Session, this_game: Game, full_length: boo
|
||||
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}')
|
||||
logger.info(f'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}',
|
||||
@ -64,7 +64,7 @@ async def get_scorebug_embed(session: Session, this_game: Game, full_length: boo
|
||||
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')
|
||||
logger.debug(f'get_scorebug_embed - Could not initialize play')
|
||||
|
||||
if curr_play is not None:
|
||||
embed.add_field(
|
||||
@ -72,6 +72,7 @@ async def get_scorebug_embed(session: Session, this_game: Game, full_length: boo
|
||||
value=curr_play.scorebug_ascii,
|
||||
inline=False
|
||||
)
|
||||
logger.info(f'curr_play: {curr_play}')
|
||||
|
||||
def steal_string(batting_card: BattingCard) -> str:
|
||||
steal_string = '-/- (---)'
|
||||
@ -244,6 +245,20 @@ def starting_pitcher_dropdown_view(session: Session, this_game: Game, human_team
|
||||
return DropdownView(dropdown_objects=[sp_selection])
|
||||
|
||||
|
||||
def sub_batter_dropdown_view(session: Session, this_game: Game, human_team: Team, batting_order: int):
|
||||
batters = get_available_batters(session, this_game, human_team)
|
||||
logger.info(f'batters: {batters}')
|
||||
bat_selection = SelectBatterSub(
|
||||
this_game=this_game,
|
||||
this_team=human_team,
|
||||
session=session,
|
||||
batting_order=batting_order,
|
||||
options=[SelectOption(label=f'{x.batterscouting.battingcard.hand.upper()} | {x.player.name_with_desc}', value=x.id) for x in batters],
|
||||
placeholder='Select your Sub'
|
||||
)
|
||||
return DropdownView(dropdown_objects=[bat_selection])
|
||||
|
||||
|
||||
async def read_lineup(session: Session, interaction: discord.Interaction, this_game: Game, lineup_team: Team, sheets_auth, lineup: Choice[str], league_name: str):
|
||||
"""
|
||||
Commits lineups and rosterlinks
|
||||
@ -368,10 +383,12 @@ def complete_play(session:Session, this_play: Play):
|
||||
"""
|
||||
Commits this_play and new_play
|
||||
"""
|
||||
logger.info(f'Completing play {this_play.id} in game {this_play.game.id}')
|
||||
nso = this_play.starting_outs + this_play.outs
|
||||
runs_scored = 0
|
||||
on_first, on_second, on_third = None, None, None
|
||||
|
||||
logger.info(f'Running bulk checks')
|
||||
is_go_ahead = False
|
||||
if nso >= 3:
|
||||
switch_sides = True
|
||||
@ -435,12 +452,14 @@ def complete_play(session:Session, this_play: Play):
|
||||
|
||||
obc = get_obc(on_first, on_second, on_third)
|
||||
|
||||
logger.info(f'Calculating re24')
|
||||
this_play.re24 = get_re24(this_play, runs_scored, new_obc=obc, new_starting_outs=nso)
|
||||
|
||||
if nbo > 9:
|
||||
nbo = 1
|
||||
|
||||
new_batter = get_one_lineup(session, this_play.game, new_batter_team, batting_order=nbo)
|
||||
logger.info(f'new_batter: {new_batter}')
|
||||
|
||||
new_play = Play(
|
||||
game=this_play.game,
|
||||
@ -468,6 +487,10 @@ def complete_play(session:Session, this_play: Play):
|
||||
this_play.wpa = get_wpa(this_play, new_play)
|
||||
this_play.locked = False
|
||||
this_play.complete = True
|
||||
|
||||
logger.info(f'this_play: {this_play}')
|
||||
logger.info(f'new_play: {new_play}')
|
||||
|
||||
session.add(this_play)
|
||||
session.add(new_play)
|
||||
session.commit()
|
||||
@ -2069,22 +2092,22 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
|
||||
elif hit_result == 'G1':
|
||||
if this_play.on_first is not None and this_play.starting_outs < 2:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'B', position=this_play.check_pos, defender_is_in=defender_is_in)
|
||||
this_play = await gb_letter(session, interaction, this_play, 'B', position=this_play.check_pos, defender_is_in=playing_in)
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'A', position=this_play.check_pos, defender_is_in=defender_is_in)
|
||||
this_play = await gb_letter(session, interaction, this_play, 'A', position=this_play.check_pos, defender_is_in=playing_in)
|
||||
|
||||
elif hit_result == 'G2':
|
||||
if this_play.on_base_code > 0:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'C', position=this_play.check_pos, defender_is_in=defender_is_in)
|
||||
this_play = await gb_letter(session, interaction, this_play, 'C', position=this_play.check_pos, defender_is_in=playing_in)
|
||||
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'B', position=this_play.check_pos, defender_is_in=defender_is_in)
|
||||
this_play = await gb_letter(session, interaction, this_play, 'B', position=this_play.check_pos, defender_is_in=playing_in)
|
||||
|
||||
elif hit_result == 'G3':
|
||||
if this_play.on_base_code > 0:
|
||||
this_play = await singles(session, interaction, this_play, '*')
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'C', position=this_play.check_pos, defender_is_in=defender_is_in)
|
||||
this_play = await gb_letter(session, interaction, this_play, 'C', position=this_play.check_pos, defender_is_in=playing_in)
|
||||
|
||||
elif hit_result == 'SPD':
|
||||
this_play = singles(session, interaction, this_play, '*')
|
||||
@ -2136,29 +2159,29 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
to_right_side = position in ['1B', '2B']
|
||||
|
||||
if 'G3' in hit_result:
|
||||
if this_play.on_base_code == 2 and not defender_is_in:
|
||||
if this_play.on_base_code == 2 and not playing_in:
|
||||
this_play = await gb_result(session, interaction, this_play, 12)
|
||||
|
||||
elif defender_is_in and this_play.on_base_code == 5:
|
||||
elif playing_in and this_play.on_base_code == 5:
|
||||
this_play = await gb_result(session, interaction, this_play, 7, to_mif, to_right_side)
|
||||
|
||||
elif defender_is_in and this_play.on_base_code in [3, 6]:
|
||||
elif playing_in and this_play.on_base_code in [3, 6]:
|
||||
this_play = await gb_decide(session, interaction=interaction, this_play=this_play)
|
||||
|
||||
elif defender_is_in and this_play.on_base_code == 7:
|
||||
elif playing_in and this_play.on_base_code == 7:
|
||||
this_play = await gb_result(session, interaction, this_play, 11)
|
||||
|
||||
else:
|
||||
this_play = await gb_result(session, interaction, this_play, 3)
|
||||
|
||||
elif 'G2' in hit_result:
|
||||
if this_play.on_base_code == 7 and defender_is_in:
|
||||
if this_play.on_base_code == 7 and playing_in:
|
||||
this_play = await gb_result(session, interaction, this_play, 11)
|
||||
|
||||
elif not defender_is_in and this_play.on_base_code in [3, 6]:
|
||||
elif not playing_in and this_play.on_base_code in [3, 6]:
|
||||
this_play = await gb_result(session, interaction, this_play, 5, to_mif=to_mif)
|
||||
|
||||
elif defender_is_in and this_play.on_base_code in [3, 5, 6]:
|
||||
elif playing_in and this_play.on_base_code in [3, 5, 6]:
|
||||
this_play = await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
elif this_play.on_base_code == 2:
|
||||
@ -2168,16 +2191,16 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
this_play = await gb_result(session, interaction, this_play, 4)
|
||||
|
||||
elif 'G1' in hit_result:
|
||||
if this_play.on_base_code == 7 and defender_is_in:
|
||||
if this_play.on_base_code == 7 and playing_in:
|
||||
this_play = await gb_result(session, interaction, this_play, 10)
|
||||
|
||||
elif not defender_is_in and this_play.on_base_code == 4:
|
||||
elif not playing_in and this_play.on_base_code == 4:
|
||||
this_play = await gb_result(session, interaction, this_play, 13)
|
||||
|
||||
elif not defender_is_in and this_play.on_base_code in [3, 6]:
|
||||
elif not playing_in and this_play.on_base_code in [3, 6]:
|
||||
this_play = await gb_result(session, interaction, this_play, 3)
|
||||
|
||||
elif defender_is_in and this_play.on_base_code in [3, 5, 6]:
|
||||
elif playing_in and this_play.on_base_code in [3, 5, 6]:
|
||||
this_play = await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
elif this_play.on_base_code == 2:
|
||||
@ -2264,8 +2287,10 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
|
||||
|
||||
def activate_last_play(session: Session, this_game: Game) -> Play:
|
||||
logger.info(f'Pulling last play to complete and advance')
|
||||
p_query = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(1)).all()
|
||||
|
||||
logger.info(f'last play: {p_query[0].id}')
|
||||
this_play = complete_play(session, p_query[0])
|
||||
|
||||
return this_play
|
||||
@ -2273,6 +2298,7 @@ def activate_last_play(session: Session, this_game: Game) -> Play:
|
||||
|
||||
def undo_play(session: Session, this_play: Play):
|
||||
this_game = this_play.game
|
||||
after_play_min = max(1, this_play.play_num - 2)
|
||||
|
||||
last_two_plays = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(2)).all()
|
||||
|
||||
@ -2286,12 +2312,27 @@ def undo_play(session: Session, this_play: Play):
|
||||
last_two_ids = [last_two_plays[0].id, last_two_plays[1].id]
|
||||
logger.warning(f'Deleting plays: {last_two_ids}')
|
||||
session.exec(delete(Play).where(Play.id.in_(last_two_ids)))
|
||||
|
||||
new_player_ids = []
|
||||
new_players = session.exec(select(Lineup).where(Lineup.game == this_game, Lineup.after_play >= after_play_min)).all()
|
||||
logger.info(f'Subs to roll back: {new_players}')
|
||||
for lineup in new_players:
|
||||
new_players.append(lineup.id)
|
||||
old_player = session.get(Lineup, lineup.replacing_id)
|
||||
old_player.active = True
|
||||
session.add(old_player)
|
||||
|
||||
logger.warning(f'Deleting lineup IDs: {new_player_ids}')
|
||||
session.exec(delete(Lineup).where(Lineup.id.in_(new_player_ids)))
|
||||
|
||||
session.commit()
|
||||
|
||||
try:
|
||||
logger.info(f'Attempting to initialize play for Game {this_game.id}...')
|
||||
this_play = this_game.initialize_play(session)
|
||||
logger.info(f'Initialized play: {this_play.id}')
|
||||
except PlayInitException:
|
||||
logger.info(f'Plays found, attempting to active the last play')
|
||||
this_play = activate_last_play(session, this_game)
|
||||
logger.info(f'Re-activated play: {this_play.id}')
|
||||
|
||||
|
||||
@ -163,192 +163,6 @@ class Game(SQLModel, table=True):
|
||||
return this_play[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
# 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)
|
||||
# )
|
||||
|
||||
# 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 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}'
|
||||
# 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}')
|
||||
|
||||
# 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
|
||||
# )
|
||||
|
||||
# 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):
|
||||
"""
|
||||
@ -722,6 +536,9 @@ class ManagerAi(ManagerAiBase, table=True):
|
||||
this_resp.outfield_in = True
|
||||
this_resp.infield_in = True
|
||||
this_resp.ai_note += f'- play the outfield and infield in'
|
||||
elif this_play.on_first and this_play.starting_outs == 1:
|
||||
this_resp.corners_in = True
|
||||
this_resp.ai_note += f'- play the corners in\n'
|
||||
elif abs(this_play.away_score - this_play.home_score) <= 3:
|
||||
this_resp.infield_in = True
|
||||
this_resp.ai_note += f'- play the whole infield in\n'
|
||||
|
||||
@ -129,17 +129,19 @@ async def get_team_or_none(
|
||||
|
||||
|
||||
async def get_player_or_none(session: Session, player_id: int, skip_cache: bool = False) -> Player | None:
|
||||
logger.info(f'gameplay_models - get_player_or_none - player_id: {player_id}')
|
||||
logger.info(f'gameplay_models - get_player_or_none - player_id: {player_id} / skip_cache: {skip_cache}')
|
||||
if not skip_cache:
|
||||
this_player = session.get(Player, player_id)
|
||||
|
||||
if this_player is not None:
|
||||
logger.info(f'we found a cached player: {this_player} / created: {this_player.created}')
|
||||
logger.info(f'we found a cached player: {this_player}\ncreated: {this_player.created}')
|
||||
tdelta = datetime.datetime.now() - this_player.created
|
||||
logger.debug(f'tdelta: {tdelta}')
|
||||
logger.info(f'tdelta: {tdelta}')
|
||||
if tdelta.total_seconds() < CACHE_LIMIT:
|
||||
logger.info(f'returning this player')
|
||||
return this_player
|
||||
else:
|
||||
logger.warning('Deleting old player record')
|
||||
session.delete(this_player)
|
||||
session.commit()
|
||||
|
||||
@ -164,37 +166,29 @@ async def get_player_or_none(session: Session, player_id: int, skip_cache: bool
|
||||
|
||||
|
||||
async def get_batter_scouting_or_none(session: Session, card: Card, skip_cache: bool = False) -> BatterScouting | None:
|
||||
logger.info(f'Getting batting scouting for card ID #{card.id}: {card.player.name_with_desc}')
|
||||
logger.info(f'Getting batting scouting for card ID #{card.id}: {card.player.name_with_desc} / skip_cache: {skip_cache}')
|
||||
|
||||
s_query = await db_get(f'battingcardratings/player/{card.player.id}', none_okay=False)
|
||||
if s_query['count'] != 2:
|
||||
log_exception(DatabaseError, f'Scouting for {card.player.name_with_desc} was not found.')
|
||||
|
||||
this_scouting = session.get(BattingCard, s_query['ratings'][0]['battingcard']['id'])
|
||||
this_scouting = session.exec(select(BatterScouting).where(BatterScouting.battingcard_id == s_query['ratings'][0]['battingcard']['id'])).all()
|
||||
logger.info(f'this_scouting: {this_scouting}')
|
||||
# this_scouting = session.get(BatterScouting, s_query['ratings'][0]['battingcard']['id'])
|
||||
|
||||
if this_scouting is not None:
|
||||
if len(this_scouting) > 0:
|
||||
logger.info(f'we found a cached scouting: {this_scouting} / created {this_scouting.created}')
|
||||
tdelta = datetime.datetime.now() - this_scouting.created
|
||||
logger.debug(f'tdelta: {tdelta}')
|
||||
if tdelta.total_seconds() < CACHE_LIMIT:
|
||||
return this_scouting
|
||||
else:
|
||||
session.delete(this_scouting.battingcard)
|
||||
session.delete(this_scouting.ratings_vl)
|
||||
session.delete(this_scouting.ratings_vr)
|
||||
session.delete(this_scouting)
|
||||
session.commit()
|
||||
|
||||
# if not skip_cache and card.batterscouting is not None:
|
||||
# this_scouting = session.get(BatterScouting, card.batterscouting.id)
|
||||
|
||||
# if this_scouting is not None:
|
||||
# logger.info(f'we found a cached scouting: {this_scouting} / created {this_scouting.created}')
|
||||
# tdelta = datetime.datetime.now() - this_scouting.created
|
||||
# logger.debug(f'tdelta: {tdelta}')
|
||||
# if tdelta.total_seconds() < CACHE_LIMIT:
|
||||
# return this_scouting
|
||||
# else:
|
||||
# session.delete(this_scouting)
|
||||
# session.commit()
|
||||
|
||||
def cache_scouting(batting_card: dict, ratings_vr: dict, ratings_vl: dict) -> BatterScouting:
|
||||
valid_bc = BattingCardBase.model_validate(batting_card, from_attributes=True)
|
||||
db_bc = BattingCard.model_validate(valid_bc)
|
||||
@ -212,8 +206,10 @@ async def get_batter_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
)
|
||||
|
||||
session.add(db_scouting)
|
||||
logger.info(f'caching scouting')
|
||||
session.commit()
|
||||
session.refresh(db_scouting)
|
||||
logger.info(f'scouting id: {db_scouting.id} / battingcard: {db_scouting.battingcard.id} / vL: {db_scouting.ratings_vl.id} / vR: {db_scouting.ratings_vr.id}')
|
||||
return db_scouting
|
||||
|
||||
return cache_scouting(
|
||||
@ -222,16 +218,6 @@ async def get_batter_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
ratings_vl=s_query['ratings'][0] if s_query['ratings'][0]['vs_hand'] == 'L' else s_query['ratings'][1]
|
||||
)
|
||||
|
||||
# s_query = await db_get(f'battingcardratings/player/{card.player.id}', none_okay=False)
|
||||
# if s_query['count'] == 2:
|
||||
# return cache_scouting(
|
||||
# batting_card=s_query['ratings'][0]['battingcard'],
|
||||
# ratings_vr=s_query['ratings'][0] if s_query['ratings'][0]['vs_hand'] == 'R' else s_query['ratings'][1],
|
||||
# ratings_vl=s_query['ratings'][0] if s_query['ratings'][0]['vs_hand'] == 'L' else s_query['ratings'][1]
|
||||
# )
|
||||
|
||||
# return None
|
||||
|
||||
|
||||
async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache: bool = False) -> PitcherScouting | None:
|
||||
logger.info(f'Getting pitching scouting for card ID #{card.id}: {card.player.name_with_desc}')
|
||||
@ -240,9 +226,11 @@ async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
if s_query['count'] != 2:
|
||||
log_exception(DatabaseError, f'Scouting for {card.player.name_with_desc} was not found.')
|
||||
|
||||
this_scouting = session.get(PitcherScouting, s_query['ratings'][0]['pitchingcard']['id'])
|
||||
this_scouting = session.exec(select(PitcherScouting).where(PitcherScouting.pitchingcard_id == s_query['ratings'][0]['pitchingcard']['id'])).all()
|
||||
logger.info(f'this_scouting: {this_scouting}')
|
||||
# this_scouting = session.get(PitcherScouting, s_query['ratings'][0]['pitchingcard']['id'])
|
||||
|
||||
if this_scouting is not None:
|
||||
if len(this_scouting) > 0:
|
||||
logger.info(f'we found a cached scouting: {this_scouting} / created {this_scouting.created}')
|
||||
tdelta = datetime.datetime.now() - this_scouting.created
|
||||
logger.debug(f'tdelta: {tdelta}')
|
||||
@ -251,6 +239,9 @@ async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
return this_scouting
|
||||
|
||||
else:
|
||||
session.delete(this_scouting.pitchingcard)
|
||||
session.delete(this_scouting.ratings_vl)
|
||||
session.delete(this_scouting.ratings_vr)
|
||||
session.delete(this_scouting)
|
||||
session.commit()
|
||||
|
||||
@ -271,8 +262,10 @@ async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
)
|
||||
|
||||
session.add(db_scouting)
|
||||
logger.info(f'caching scouting')
|
||||
session.commit()
|
||||
session.refresh(db_scouting)
|
||||
logger.info(f'scouting id: {db_scouting.id} / pitching: {db_scouting.pitchingcard.id} / vL: {db_scouting.ratings_vl.id} / vR: {db_scouting.ratings_vr.id}')
|
||||
return db_scouting
|
||||
|
||||
scouting = cache_scouting(
|
||||
@ -394,7 +387,7 @@ async def shared_get_scouting(session: Session, this_card: Card, which: Literal[
|
||||
|
||||
|
||||
async def get_position(session: Session, this_card: Card, position: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF'], skip_cache: bool = False) -> PositionRating:
|
||||
logger.info(f'Pulling position rating for {this_card.player.name_with_desc} at {position}')
|
||||
logger.info(f'Pulling position rating for {this_card.player.name_with_desc} at {position} / skip_cache: {skip_cache}')
|
||||
if not skip_cache:
|
||||
this_pos = session.exec(select(PositionRating).where(PositionRating.player_id == this_card.player.id, PositionRating.position == position, PositionRating.variant == this_card.variant)).all()
|
||||
logger.info(f'Ratings found: {len(this_pos)}')
|
||||
@ -435,7 +428,7 @@ async def get_position(session: Session, this_card: Card, position: Literal['P',
|
||||
|
||||
|
||||
async def get_or_create_ai_card(session: Session, player: Player, team: Team, skip_cache: bool = False, dev_mode: bool = False) -> Card:
|
||||
logger.info(f'Getting or creating card for {player.name_with_desc} on the {team.sname}')
|
||||
logger.info(f'Getting or creating card for {player.name_with_desc} on the {team.sname} / skip_cache: {skip_cache}')
|
||||
if not team.is_ai:
|
||||
err = f'Cannot create AI cards for human teams'
|
||||
logger.error(f'gameplay_models - get_or_create_ai_card: {err}')
|
||||
@ -453,6 +446,7 @@ async def get_or_create_ai_card(session: Session, player: Player, team: Team, sk
|
||||
if tdelta.total_seconds() < CACHE_LIMIT:
|
||||
return this_card
|
||||
else:
|
||||
logger.info(f'deleting card record')
|
||||
session.delete(this_card)
|
||||
session.commit()
|
||||
|
||||
@ -520,7 +514,7 @@ async def get_or_create_ai_card(session: Session, player: Player, team: Team, sk
|
||||
|
||||
|
||||
async def get_card_or_none(session: Session, card_id: int, skip_cache: bool = False) -> Card | None:
|
||||
logger.info(f'Getting card {card_id}')
|
||||
logger.info(f'Getting card {card_id} / skip_cache: {skip_cache}')
|
||||
if not skip_cache:
|
||||
this_card = session.get(Card, card_id)
|
||||
|
||||
@ -886,8 +880,10 @@ async def post_game_rewards(session: Session, winning_team: Team, losing_team: T
|
||||
|
||||
|
||||
def get_available_subs(session: Session, this_game: Game, this_team: Team) -> list[Card]:
|
||||
logger.info(f'Getting all available subs')
|
||||
team_lineups = session.exec(select(Lineup).where(Lineup.game == this_game, Lineup.team == this_team)).all()
|
||||
used_card_ids = [x.card.id for x in team_lineups]
|
||||
logger.info(f'USED CARD IDS: {used_card_ids}')
|
||||
|
||||
all_roster_links = session.exec(select(RosterLink).where(RosterLink.game == this_game, RosterLink.team == this_team)).all()
|
||||
|
||||
|
||||
@ -41,11 +41,11 @@ class DefenseResponse(AiResponse):
|
||||
corners_in: bool = False
|
||||
|
||||
def defender_in(self, position: str):
|
||||
if self.infield_in and position in ['C', '1B', '2B', '3B', 'SS', 'P']:
|
||||
if self.infield_in and (position in ['C', '1B', '2B', '3B', 'SS', 'P']):
|
||||
return True
|
||||
elif self.corners_in and position in ['C', '1B', '3B', 'P']:
|
||||
elif self.corners_in and (position in ['C', '1B', '3B', 'P']):
|
||||
return True
|
||||
elif self.outfield_in and position in ['LF', 'CF', 'RF']:
|
||||
elif self.outfield_in and (position in ['LF', 'CF', 'RF']):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import discord
|
||||
from typing import Coroutine, Literal
|
||||
|
||||
from dice import ab_roll, jump_roll
|
||||
from exceptions import *
|
||||
from in_game.gameplay_models import Game, Play, Team
|
||||
|
||||
|
||||
@ -51,34 +52,59 @@ class Confirm(discord.ui.View):
|
||||
|
||||
|
||||
class ButtonOptions(discord.ui.View):
|
||||
def __init__(self, responders: list, timeout: float = 300.0, labels=None):
|
||||
def __init__(self, labels: list[str], responders: list, timeout: float = 300.0, disable_chosen: bool = False):
|
||||
logger.info(f'ButtonOptions - labels: {labels} / responders: {responders} / timeout: {timeout} / disable_chosen: {disable_chosen}')
|
||||
|
||||
super().__init__(timeout=timeout)
|
||||
if not isinstance(responders, list):
|
||||
raise TypeError('responders must be a list')
|
||||
if len(labels) > 5 or len(labels) < 1:
|
||||
log_exception(ValueError, 'ButtonOptions support between 1 and 5 options')
|
||||
|
||||
self.value = None
|
||||
self.responders = responders
|
||||
self.options = labels
|
||||
self.disable_chosen = disable_chosen
|
||||
# if len(labels) == 5:
|
||||
# for count, x in enumerate(labels):
|
||||
# if count == 0:
|
||||
# self.option1.label = x
|
||||
# if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
# self.remove_item(self.option1)
|
||||
# if count == 1:
|
||||
# self.option2.label = x
|
||||
# if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
# self.remove_item(self.option2)
|
||||
# if count == 2:
|
||||
# self.option3.label = x
|
||||
# if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
# self.remove_item(self.option3)
|
||||
# if count == 3:
|
||||
# self.option4.label = x
|
||||
# if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
# self.remove_item(self.option4)
|
||||
# if count == 4:
|
||||
# self.option5.label = x
|
||||
# if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
# self.remove_item(self.option5)
|
||||
|
||||
# else:
|
||||
all_options = [self.option1, self.option2, self.option3, self.option4, self.option5]
|
||||
logger.info(f'all_options: {all_options}')
|
||||
for count, x in enumerate(labels):
|
||||
if count == 0:
|
||||
self.option1.label = x
|
||||
if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
self.remove_item(self.option1)
|
||||
if count == 1:
|
||||
self.option2.label = x
|
||||
if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
self.remove_item(self.option2)
|
||||
if count == 2:
|
||||
self.option3.label = x
|
||||
if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
self.remove_item(self.option3)
|
||||
if count == 3:
|
||||
self.option4.label = x
|
||||
if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
self.remove_item(self.option4)
|
||||
if count == 4:
|
||||
self.option5.label = x
|
||||
if x is None or x.lower() == 'na' or x == 'N/A':
|
||||
self.remove_item(self.option5)
|
||||
if x is None or x.lower() == 'na' or x.lower() == 'n/a':
|
||||
self.remove_item(all_options[count])
|
||||
else:
|
||||
all_options[count].label = x
|
||||
|
||||
if len(labels) < 2:
|
||||
self.remove_item(self.option2)
|
||||
if len(labels) < 3:
|
||||
self.remove_item(self.option3)
|
||||
if len(labels) < 4:
|
||||
self.remove_item(self.option4)
|
||||
if len(labels) < 5:
|
||||
self.remove_item(self.option5)
|
||||
|
||||
@discord.ui.button(label='Option 1', style=discord.ButtonStyle.primary)
|
||||
async def option1(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@ -89,9 +115,11 @@ class ButtonOptions(discord.ui.View):
|
||||
delete_after=10.0
|
||||
)
|
||||
|
||||
self.value = self.options[0]
|
||||
self.clear_items()
|
||||
self.stop()
|
||||
if self.disable_chosen:
|
||||
button.disabled = True
|
||||
self.value = self.options[0]
|
||||
await interaction.edit_original_response(view=self)
|
||||
|
||||
@discord.ui.button(label='Option 2', style=discord.ButtonStyle.primary)
|
||||
async def option2(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@ -102,9 +130,11 @@ class ButtonOptions(discord.ui.View):
|
||||
delete_after=10.0
|
||||
)
|
||||
|
||||
self.value = self.options[1]
|
||||
self.clear_items()
|
||||
self.stop()
|
||||
if self.disable_chosen:
|
||||
button.disabled = True
|
||||
self.value = self.options[1]
|
||||
await interaction.edit_original_response(view=self)
|
||||
|
||||
@discord.ui.button(label='Option 3', style=discord.ButtonStyle.primary)
|
||||
async def option3(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@ -115,9 +145,11 @@ class ButtonOptions(discord.ui.View):
|
||||
delete_after=10.0
|
||||
)
|
||||
|
||||
self.value = self.options[2]
|
||||
self.clear_items()
|
||||
self.stop()
|
||||
if self.disable_chosen:
|
||||
button.disabled = True
|
||||
self.value = self.options[2]
|
||||
await interaction.edit_original_response(view=self)
|
||||
|
||||
@discord.ui.button(label='Option 4', style=discord.ButtonStyle.primary)
|
||||
async def option4(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@ -128,9 +160,11 @@ class ButtonOptions(discord.ui.View):
|
||||
delete_after=10.0
|
||||
)
|
||||
|
||||
self.value = self.options[3]
|
||||
self.clear_items()
|
||||
self.stop()
|
||||
if self.disable_chosen:
|
||||
button.disabled = True
|
||||
self.value = self.options[3]
|
||||
await interaction.edit_original_response(view=self)
|
||||
|
||||
@discord.ui.button(label='Option 5', style=discord.ButtonStyle.primary)
|
||||
async def option5(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
@ -141,9 +175,11 @@ class ButtonOptions(discord.ui.View):
|
||||
delete_after=10.0
|
||||
)
|
||||
|
||||
self.value = self.options[4]
|
||||
self.clear_items()
|
||||
self.stop()
|
||||
if self.disable_chosen:
|
||||
button.disabled = True
|
||||
self.value = self.options[4]
|
||||
await interaction.edit_original_response(view=self)
|
||||
|
||||
|
||||
async def ask_confirm(interaction: discord.Interaction, question: str, label_type: Literal['yes', 'confirm'] = 'confirm', timeout: int = 60, delete_question: bool = True, custom_confirm_label: str = None, custom_cancel_label: str = None, embed: discord.Embed = None, delete_embed: bool = False) -> bool:
|
||||
@ -177,6 +213,87 @@ async def ask_confirm(interaction: discord.Interaction, question: str, label_typ
|
||||
return False
|
||||
|
||||
|
||||
async def ask_with_buttons(interaction: discord.Interaction, button_options: list[str], question: str = None, timeout: int = 60, delete_question: bool = True, embeds: list[discord.Embed] = None, delete_embeds: bool = False, edit_original_interaction: bool = False, none_okay: bool = False) -> str:
|
||||
"""
|
||||
Returns text of button pressed
|
||||
"""
|
||||
logger.info(f'ask_with_buttons - button_options: {button_options} / question: {question} / timeout: {timeout} / delete_question: {delete_question} / embeds: {embeds} / delete_embeds: {delete_embeds} / edit_original_transaction: {edit_original_interaction}')
|
||||
|
||||
if question is None and embeds is None:
|
||||
log_exception(KeyError, 'At least one of question or embed must be provided')
|
||||
|
||||
view = ButtonOptions(
|
||||
responders=[interaction.user],
|
||||
timeout=timeout,
|
||||
labels=button_options
|
||||
)
|
||||
logger.info(f'view: {view}')
|
||||
# if edit_original_interaction:
|
||||
# logger.info(f'editing message')
|
||||
# q_message = await interaction.edit_original_response(
|
||||
# content=question,
|
||||
# view=view,
|
||||
# embeds=embeds
|
||||
# )
|
||||
# logger.info(f'edited')
|
||||
# else:
|
||||
# logger.info(f'posting message')
|
||||
# q_message = await interaction.channel.send(
|
||||
# content=question,
|
||||
# view=view,
|
||||
# embeds=embeds
|
||||
# )
|
||||
logger.info(f'posting message')
|
||||
q_message = await interaction.channel.send(
|
||||
content=question,
|
||||
view=view,
|
||||
embeds=embeds
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
return_val = view.value
|
||||
|
||||
else:
|
||||
return_val = None
|
||||
|
||||
if question is not None and embeds is not None:
|
||||
logger.info(f'checking for deletion with question and embeds')
|
||||
if delete_question and delete_embeds:
|
||||
logger.info(f'delete it all')
|
||||
await q_message.delete()
|
||||
elif delete_question:
|
||||
logger.info(f'delete question')
|
||||
await q_message.edit(
|
||||
content=None
|
||||
)
|
||||
elif delete_embeds:
|
||||
logger.info(f'delete embeds')
|
||||
await q_message.edit(
|
||||
embeds=None
|
||||
)
|
||||
elif return_val is None:
|
||||
logger.info(f'remove view')
|
||||
await q_message.edit(
|
||||
view=None
|
||||
)
|
||||
|
||||
elif (question is not None and delete_question) or (embeds is not None and delete_embeds):
|
||||
logger.info(f'deleting message')
|
||||
await q_message.delete()
|
||||
|
||||
elif return_val is None:
|
||||
logger.info(f'No reponse, remove view')
|
||||
await q_message.edit(
|
||||
view=None
|
||||
)
|
||||
|
||||
if return_val is not None or none_okay:
|
||||
return return_val
|
||||
|
||||
log_exception(ButtonOptionNotChosen, 'Selecting an option is mandatory')
|
||||
|
||||
|
||||
class ScorebugButtons(discord.ui.View):
|
||||
def __init__(self, play: Play, embed: discord.Embed, timeout: float = 30):
|
||||
super().__init__(timeout=timeout)
|
||||
|
||||
@ -6,10 +6,11 @@ from discord import SelectOption
|
||||
from discord.utils import MISSING
|
||||
from sqlmodel import Session
|
||||
|
||||
from exceptions import CardNotFoundException, log_exception
|
||||
from exceptions import CardNotFoundException, PlayNotFoundException, log_exception
|
||||
from in_game.game_helpers import legal_check
|
||||
from in_game.gameplay_models import Game, Lineup, Play, Team
|
||||
from in_game.gameplay_queries import get_position, get_card_or_none
|
||||
from in_game.gameplay_queries import get_one_lineup, get_position, get_card_or_none
|
||||
from utilities.buttons import ask_confirm
|
||||
|
||||
|
||||
logger = logging.getLogger('discord_app')
|
||||
@ -143,6 +144,145 @@ class SelectStartingPitcher(discord.ui.Select):
|
||||
view=None
|
||||
)
|
||||
|
||||
|
||||
class SelectSubPosition(discord.ui.Select):
|
||||
def __init__(self, session: Session, this_lineup: Lineup, custom_id = ..., placeholder = None, options: List[SelectOption] = ...):
|
||||
self.session = session
|
||||
self.this_lineup = this_lineup
|
||||
super().__init__(custom_id=custom_id, placeholder=placeholder, min_values=1, max_values=1, options=options, disabled=False)
|
||||
|
||||
async def callback(self, interaction: discord.Interaction):
|
||||
logger.info(f'Setting sub position to {self.values[0]}')
|
||||
await interaction.edit_original_response(view=None)
|
||||
|
||||
if self.values[0] == 'PH':
|
||||
await interaction.channel.send(content=f'Their position is set to Pinch Hitter.')
|
||||
return
|
||||
|
||||
else:
|
||||
await get_position(self.session, self.this_lineup.card_id, position=self.values[0])
|
||||
|
||||
self.this_lineup.position = self.values[0]
|
||||
for option in self.options:
|
||||
if option.value == self.values[0]:
|
||||
this_label = option.label
|
||||
|
||||
self.this_lineup.position = self.values[0]
|
||||
self.session.add(self.this_lineup)
|
||||
self.session.commit()
|
||||
|
||||
await interaction.channel.send(content=f'Their position is set to {this_label}.')
|
||||
|
||||
|
||||
class SelectBatterSub(discord.ui.Select):
|
||||
def __init__(self, this_game: Game, this_team: Team, session: Session, batting_order: int, custom_id: str = MISSING, placeholder: str | None = None, options: List[SelectOption] = ...):
|
||||
logger.info(f'Inside SelectBatterSub init function')
|
||||
self.game = this_game
|
||||
self.team = this_team
|
||||
self.session = session
|
||||
# self.league_name = league_name
|
||||
self.batting_order = batting_order
|
||||
super().__init__(custom_id=custom_id, placeholder=placeholder, min_values=1, max_values=1, options=options)
|
||||
|
||||
|
||||
async def callback(self, interaction: discord.Interaction):
|
||||
await interaction.response.defer()
|
||||
|
||||
logger.info(f'Setting batter sub to Card ID: {self.values[0]}')
|
||||
|
||||
# Get Human batter card
|
||||
human_batter_card = await get_card_or_none(self.session, card_id=self.values[0])
|
||||
if human_batter_card is None:
|
||||
log_exception(CardNotFoundException, f'Card ID {self.values[0]} not found')
|
||||
|
||||
if human_batter_card.team_id != self.team.id:
|
||||
logger.error(f'Card_id {self.values[0]} does not belong to {self.team.abbrev} in Game {self.game.id}')
|
||||
await interaction.channel.send(
|
||||
f'Uh oh. Card ID {self.values[0]} is {human_batter_card.player.name} and belongs to {human_batter_card.team.sname}. Will you double check that before we get started?'
|
||||
)
|
||||
return
|
||||
|
||||
# legal_data = await legal_check([self.values[0]], difficulty_name=self.league_name)
|
||||
# if not legal_data['legal']:
|
||||
# await interaction.edit_original_response(
|
||||
# content=f'It looks like this is a Ranked Legal game and {human_batter_card.player.name_with_desc} is not legal in {self.league_name} games. You can start a new game once you pick a new SP.'
|
||||
# )
|
||||
# return
|
||||
|
||||
this_play = self.game.current_play_or_none(self.session)
|
||||
if this_play is None:
|
||||
log_exception(PlayNotFoundException, 'Play not found during substitution')
|
||||
logger.info(f'this_play: {this_play}')
|
||||
|
||||
last_lineup = get_one_lineup(
|
||||
session=self.session,
|
||||
this_game=self.game,
|
||||
this_team=self.team,
|
||||
active=True,
|
||||
batting_order=self.batting_order
|
||||
)
|
||||
|
||||
same_position = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Will **{human_batter_card.player.name}** replace {last_lineup.player.name} as the {last_lineup.position}?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
if same_position:
|
||||
position = last_lineup.position
|
||||
pos_text = ''
|
||||
view = None
|
||||
else:
|
||||
pos_dict_list = {
|
||||
'Pinch Hitter': 'PH',
|
||||
'Catcher': 'C',
|
||||
'First Base': '1B',
|
||||
'Second Base': '2B',
|
||||
'Third Base': '3B',
|
||||
'Shortstop': 'SS',
|
||||
'Left Field': 'LF',
|
||||
'Center Field': 'CF',
|
||||
'Right Field': 'RF',
|
||||
'Pinch Runner': 'PR',
|
||||
'Pitcher': 'P'
|
||||
}
|
||||
|
||||
position = 'PH'
|
||||
pos_text = 'What position will they play?'
|
||||
options=[SelectSubPosition(label=f'{x}', value=pos_dict_list[x], default=x=='Pinch Hitter') for x in pos_dict_list]
|
||||
|
||||
view = DropdownView(dropdown_objects=options)
|
||||
|
||||
last_lineup.active = False
|
||||
self.session.add(last_lineup)
|
||||
logger.info(f'Set {last_lineup.card.player.name_with_desc} as inactive')
|
||||
|
||||
human_bat_lineup = Lineup(
|
||||
team=self.team,
|
||||
player=human_batter_card.player,
|
||||
card=human_batter_card,
|
||||
position=position,
|
||||
batting_order=self.batting_order,
|
||||
game=self.game,
|
||||
after_play=max(this_play.play_num - 1, 0),
|
||||
replacing_id=last_lineup.id
|
||||
)
|
||||
logger.info(f'new lineup: {human_bat_lineup}')
|
||||
self.session.add(human_bat_lineup)
|
||||
# self.session.commit()
|
||||
|
||||
try:
|
||||
logger.info(f'Inserted {human_bat_lineup.card.player.name_with_desc} in the {self.batting_order} spot')
|
||||
this_play.batter = human_bat_lineup
|
||||
this_play.batter_pos = position
|
||||
except Exception as e:
|
||||
logger.error(e, exc_info=True, stack_info=True)
|
||||
|
||||
self.session.add(this_play)
|
||||
|
||||
self.session.commit()
|
||||
|
||||
await interaction.edit_original_response(
|
||||
content=f'{human_batter_card.player.name_with_desc} has entered in the {self.batting_order} spot. {pos_text}',
|
||||
view=view
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user