Added PO/FO to fielding roll
Complete /log xcheck and /log groundball
This commit is contained in:
parent
d6d3d7beb0
commit
8118b4a691
@ -11,7 +11,7 @@ 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, get_full_roster_from_sheets, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, 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, 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, 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 dice import ab_roll
|
||||
from exceptions import GameNotFoundException, GoogleSheetsException, 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
|
||||
@ -88,7 +88,7 @@ class Gameplay(commands.Cog):
|
||||
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, scorebug_embed)
|
||||
|
||||
if this_play.on_base_code == 0 and this_play.game.auto_roll and not this_play.batter.team.is_ai:
|
||||
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:
|
||||
this_ab_roll = ab_roll(this_play.batter.team, this_play.game, allow_chaos=False)
|
||||
scorebug_buttons = None
|
||||
|
||||
@ -243,6 +243,7 @@ class Gameplay(commands.Cog):
|
||||
True if home_team.is_ai else False,
|
||||
league.value
|
||||
)
|
||||
logger.info(f'Chosen SP in Game {this_game.id}: {ai_sp_lineup.player.name_with_desc}')
|
||||
await interaction.edit_original_response(
|
||||
content=f'The {ai_team.sname} are starting **{ai_sp_lineup.player.name_with_desc}**:\n\n{ai_sp_lineup.player.pitcher_card_url}'
|
||||
)
|
||||
@ -251,6 +252,7 @@ class Gameplay(commands.Cog):
|
||||
final_message = await interaction.channel.send(
|
||||
content=f'{ai_team.gmname} is filling out the {ai_team.sname} lineup card...'
|
||||
)
|
||||
logger.info(f'Pulling lineup in Game {this_game.id}')
|
||||
batter_lineups = await get_starting_lineup(
|
||||
session,
|
||||
team=ai_team,
|
||||
@ -260,12 +262,14 @@ class Gameplay(commands.Cog):
|
||||
)
|
||||
|
||||
# Check for last game settings
|
||||
logger.info(f'Checking human team\'s automation preferences...')
|
||||
g_query = session.exec(select(Game).where(or_(Game.home_team == human_team, Game.away_team == human_team)).order_by(Game.id.desc()).limit(1)).all()
|
||||
|
||||
if len(g_query) > 0:
|
||||
last_game = g_query[0]
|
||||
this_game.auto_roll = last_game.auto_roll
|
||||
this_game.roll_buttons = last_game.roll_buttons
|
||||
logger.info(f'Setting auto_roll to {last_game.auto_roll} and roll_buttons to {last_game.roll_buttons}')
|
||||
|
||||
# Commit game and lineups
|
||||
session.add(this_game)
|
||||
@ -517,6 +521,16 @@ class Gameplay(commands.Cog):
|
||||
|
||||
await self.complete_and_post_play(session, interaction, this_play)
|
||||
|
||||
@group_log.command(name='groundball', description='Groundballs: a, b, c')
|
||||
async def log_groundball(self, interaction: discord.Interaction, groundball_type: Literal['a', 'b', 'c']):
|
||||
with Session(engine) as session:
|
||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name=f'log groundball {groundball_type}')
|
||||
|
||||
logger.info(f'log groundball {groundball_type} - this_play: {this_play}')
|
||||
this_play = await groundballs(session, interaction, this_play, groundball_type)
|
||||
|
||||
await self.complete_and_post_play(session, interaction, this_play)
|
||||
|
||||
@group_log.command(name='hit-by-pitch', description='Hit by pitch: batter to first; runners advance if forced')
|
||||
async def log_hit_by_pitch(self, interaction: discord.Interaction):
|
||||
with Session(engine) as session:
|
||||
|
||||
@ -90,7 +90,7 @@ class Owner(commands.Cog):
|
||||
|
||||
@commands.command(name='sync', help='~ current guild, * global -> current, ! clear and sync current')
|
||||
@commands.is_owner()
|
||||
async def sync(self, ctx: Context, guilds: Greedy[Object], spec: Optional[Literal['~', "*", '!']] = None) -> None:
|
||||
async def sync(self, ctx: Context, guilds: Greedy[Object], spec: Optional[Literal['~', "*", '!', '^']] = None) -> None:
|
||||
"""
|
||||
!sync
|
||||
This takes all global commands within the CommandTree and sends them to Discord. (see CommandTree for more info.)
|
||||
|
||||
@ -16,6 +16,7 @@ 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.managerai_responses import DefenseResponse
|
||||
from utilities.buttons import ButtonOptions, Confirm, ask_confirm
|
||||
from utilities.dropdown import DropdownView, SelectStartingPitcher, SelectViewDefense
|
||||
from utilities.embeds import image_embed
|
||||
@ -263,7 +264,7 @@ async def read_lineup(session: Session, interaction: discord.Interaction, this_g
|
||||
|
||||
session.add(this_game)
|
||||
|
||||
human_lineups = await get_lineups_from_sheets(session, sheets_auth, this_game, this_team=lineup_team, lineup_num=lineup.name, roster_num=this_game.away_roster_id if this_game.is_ai else this_game.home_roster_id)
|
||||
human_lineups = await get_lineups_from_sheets(session, sheets_auth, this_game, this_team=lineup_team, lineup_num=lineup.name, roster_num=this_game.away_roster_id if this_game.home_team.is_ai else this_game.home_roster_id)
|
||||
|
||||
await interaction.edit_original_response(content='Heard from sheets, pulling in scouting data...')
|
||||
|
||||
@ -637,6 +638,7 @@ async def checks_log_interaction(session: Session, interaction: discord.Interact
|
||||
this_play.locked = True
|
||||
session.add(this_play)
|
||||
session.commit()
|
||||
session.refresh(this_play)
|
||||
|
||||
return this_game, owner_team, this_play
|
||||
|
||||
@ -664,12 +666,19 @@ def log_run_scored(session: Session, runner: Lineup, this_play: Play, is_earned:
|
||||
return True
|
||||
|
||||
|
||||
def advance_runners(session: Session, this_play: Play, num_bases: int, is_error: bool = False, only_forced: bool = False) -> Play:
|
||||
def advance_runners(session: Session, this_play: Play, num_bases: int, only_forced: bool = False, earned_bases: int = None) -> Play:
|
||||
"""
|
||||
No commits
|
||||
"""
|
||||
logger.info(f'Advancing runners {num_bases} bases in game {this_play.game.id}')
|
||||
if earned_bases is None:
|
||||
earned_bases = num_bases
|
||||
this_play.rbi = 0
|
||||
er_from = {
|
||||
3: True if earned_bases >= 1 else False,
|
||||
2: True if earned_bases >= 2 else False,
|
||||
1: True if earned_bases >= 3 else False
|
||||
}
|
||||
|
||||
if num_bases == 0:
|
||||
if this_play.on_first is not None:
|
||||
@ -690,13 +699,13 @@ def advance_runners(session: Session, this_play: Play, num_bases: int, is_error:
|
||||
if this_play.on_third:
|
||||
if num_bases > 0:
|
||||
this_play.on_third_final = 4
|
||||
log_run_scored(session, this_play.on_third, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_third, this_play, is_earned=er_from[3])
|
||||
this_play.rbi += 1 if er_from[3] else 0
|
||||
|
||||
if num_bases > 1:
|
||||
this_play.on_second_final = 4
|
||||
log_run_scored(session, this_play.on_second, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_second, this_play, is_earned=er_from[2])
|
||||
this_play.rbi += 1 if er_from[2] else 0
|
||||
elif num_bases == 1:
|
||||
this_play.on_second_final = 3
|
||||
else:
|
||||
@ -707,8 +716,8 @@ def advance_runners(session: Session, this_play: Play, num_bases: int, is_error:
|
||||
|
||||
if num_bases > 2:
|
||||
this_play.on_first_final = 4
|
||||
log_run_scored(session, this_play.on_first, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_first, this_play, is_earned=er_from[1])
|
||||
this_play.rbi += 1 if er_from[1] else 0
|
||||
elif num_bases == 2:
|
||||
this_play.on_first_final = 3
|
||||
elif num_bases == 1:
|
||||
@ -720,16 +729,16 @@ def advance_runners(session: Session, this_play: Play, num_bases: int, is_error:
|
||||
if this_play.on_third:
|
||||
if num_bases > 0:
|
||||
this_play.on_third_final = 4
|
||||
log_run_scored(session, this_play.on_third, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_third, this_play, is_earned=er_from[3])
|
||||
this_play.rbi += 1 if er_from[3] else 0
|
||||
else:
|
||||
this_play.on_third_final = 3
|
||||
|
||||
if this_play.on_second:
|
||||
if num_bases > 1:
|
||||
this_play.on_second_final = 4
|
||||
log_run_scored(session, this_play.on_second, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_second, this_play, is_earned=er_from[2])
|
||||
this_play.rbi += 1 if er_from[2] else 0
|
||||
elif num_bases == 1:
|
||||
this_play.on_second_final = 3
|
||||
else:
|
||||
@ -738,8 +747,8 @@ def advance_runners(session: Session, this_play: Play, num_bases: int, is_error:
|
||||
if this_play.on_first:
|
||||
if num_bases > 2:
|
||||
this_play.on_first_final = 4
|
||||
log_run_scored(session, this_play.on_first, this_play)
|
||||
this_play.rbi += 1 if not is_error else 0
|
||||
log_run_scored(session, this_play.on_first, this_play, is_earned=er_from[1])
|
||||
this_play.rbi += 1 if er_from[1] else 0
|
||||
elif num_bases == 2:
|
||||
this_play.on_first_final = 3
|
||||
elif num_bases == 1:
|
||||
@ -842,7 +851,7 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_play
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
|
||||
if this_play.starting_outs < 2:
|
||||
advance_runners(session, this_play, num_bases=1)
|
||||
this_play = advance_runners(session, this_play, num_bases=1)
|
||||
|
||||
if this_play.on_third:
|
||||
this_play.ab = 0
|
||||
@ -850,7 +859,7 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_play
|
||||
elif flyball_type == 'b' or flyball_type == 'ballpark':
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
this_play.bpfo = 1 if flyball_type == 'ballpark' else 0
|
||||
advance_runners(session, this_play, num_bases=0)
|
||||
this_play = advance_runners(session, this_play, num_bases=0)
|
||||
|
||||
if this_play.starting_outs < 2 and this_play.on_third:
|
||||
this_play.ab = 0
|
||||
@ -951,7 +960,7 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_play
|
||||
|
||||
elif flyball_type == 'c':
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
advance_runners(session, this_play, num_bases=0)
|
||||
this_play = advance_runners(session, this_play, num_bases=0)
|
||||
|
||||
session.add(this_play)
|
||||
session.commit()
|
||||
@ -1238,14 +1247,14 @@ async def singles(session: Session, interaction: discord.Interaction, this_play:
|
||||
this_play.hit, this_play.batter_final = 1, 1
|
||||
|
||||
if single_type == '**':
|
||||
advance_runners(session, this_play, num_bases=2)
|
||||
this_play = advance_runners(session, this_play, num_bases=2)
|
||||
|
||||
elif single_type in ['*', 'ballpark']:
|
||||
advance_runners(session, this_play, num_bases=1)
|
||||
this_play = advance_runners(session, this_play, num_bases=1)
|
||||
this_play.bp1b = 1 if single_type == 'ballpark' else 0
|
||||
|
||||
elif single_type == 'uncapped':
|
||||
advance_runners(session, this_play, 1)
|
||||
this_play = advance_runners(session, this_play, 1)
|
||||
|
||||
if this_play.on_base_code in [1, 2, 4, 5, 6, 7]:
|
||||
if this_play.on_second:
|
||||
@ -1535,8 +1544,10 @@ async def chaos(session: Session, interaction: discord.Interaction, this_play: P
|
||||
session.refresh(this_play)
|
||||
return this_play
|
||||
|
||||
|
||||
async def steals(session: Session, interaction: discord.Interaction, this_play: Play, steal_type: Literal['stolen-base', 'caught-stealing', 'steal-plus-overthrow'], to_base: Literal[2, 3, 4]) -> Play:
|
||||
advance_runners(session, this_play, 0)
|
||||
this_play = advance_runners(session, this_play, 0)
|
||||
this_play.pa = 0
|
||||
|
||||
if steal_type in ['stolen-base', 'steal-plus-overthrow']:
|
||||
this_play.sb = 1
|
||||
@ -1602,7 +1613,8 @@ async def steals(session: Session, interaction: discord.Interaction, this_play:
|
||||
session.refresh(this_play)
|
||||
return this_play
|
||||
|
||||
async def xchecks(session: Session, interaction: discord.Interaction, this_play: Play, position: str) -> Play:
|
||||
|
||||
async def xchecks(session: Session, interaction: discord.Interaction, this_play: Play, position: str, debug: bool = False) -> Play:
|
||||
defense_team = this_play.pitcher.team
|
||||
this_defender = get_one_lineup(
|
||||
session,
|
||||
@ -1610,43 +1622,72 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
this_team=defense_team,
|
||||
position=position
|
||||
)
|
||||
this_play.defender = this_defender
|
||||
this_play.check_pos = position
|
||||
def_alignment = this_play.managerai.defense_alignment(session, this_play.game)
|
||||
defender_is_in = def_alignment.defender_in(position)
|
||||
playing_in = False
|
||||
|
||||
defender_embed = defense_team.embed
|
||||
defender_embed.title = f'{defense_team.sname} {position} Check'
|
||||
defender_embed.description = f'{this_defender.player.name}'
|
||||
defender_embed.set_image(url=this_defender.player.image)
|
||||
embeds = [defender_embed]
|
||||
logger.info(f'defender_embed: {defender_embed}')
|
||||
# if not debug:
|
||||
# await interaction.edit_original_response(content=None, embeds=embeds)
|
||||
|
||||
this_rating = await get_position(session, this_defender.card, position)
|
||||
logger.info(f'position rating: {this_rating}')
|
||||
|
||||
if this_play.on_third is not None:
|
||||
if not this_play.ai_is_batting and defender_is_in:
|
||||
playing_in = True
|
||||
|
||||
elif this_play.ai_is_batting:
|
||||
playing_in = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_defender.card.player.name} playing in?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
if playing_in:
|
||||
this_rating.range = min(this_rating.range + 1, 5)
|
||||
|
||||
this_roll = sa_fielding_roll(defense_team, this_play, position, this_rating)
|
||||
logger.info(f'this_roll: {this_roll}')
|
||||
|
||||
question = f'Looks like this is a {this_roll.hit_result}'
|
||||
if this_roll.is_chaos:
|
||||
question += ' **rare play**.'
|
||||
elif this_roll.error_result is not None:
|
||||
question += f' plus {this_roll.error_result}-base error.'
|
||||
question += f'Is that correct?'
|
||||
if not debug:
|
||||
question = f'Looks like this is a **{this_roll.hit_result}**'
|
||||
if this_roll.is_chaos:
|
||||
question += ' **rare play**'
|
||||
elif this_roll.error_result is not None:
|
||||
question += f' plus {this_roll.error_result}-base error'
|
||||
question += f'. Is that correct?'
|
||||
|
||||
await interaction.edit_original_response(
|
||||
content=None,
|
||||
embeds=this_roll.embeds
|
||||
)
|
||||
is_correct = await ask_confirm(
|
||||
interaction,
|
||||
question,
|
||||
label_type='yes',
|
||||
timeout=30,
|
||||
)
|
||||
await interaction.edit_original_response(
|
||||
content=None,
|
||||
embeds=[defender_embed, *this_roll.embeds]
|
||||
)
|
||||
is_correct = await ask_confirm(
|
||||
interaction,
|
||||
question,
|
||||
label_type='yes',
|
||||
timeout=30,
|
||||
)
|
||||
else:
|
||||
is_correct = True
|
||||
|
||||
hit_result = this_roll.hit_result
|
||||
error_result = this_roll.error_result
|
||||
is_rare_play = this_roll.is_chaos
|
||||
|
||||
logger.info(f'X-Check in Game #{this_play.game_id} at {this_play.check_pos} for {this_play.defender.card.player.name_with_desc} of the {this_play.pitcher.team.sname} / hit_result: {hit_result} / error_result: {error_result} / is_correct: {is_correct}')
|
||||
|
||||
if not is_correct:
|
||||
# Full questionnaire
|
||||
pass
|
||||
|
||||
if hit_result == 'SPD':
|
||||
if hit_result == 'SPD' and not is_rare_play:
|
||||
is_out = ask_confirm(
|
||||
interaction,
|
||||
f'Is {this_play.batter.player.name} thrown out at first?',
|
||||
@ -1657,14 +1698,284 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
hit_result = 'G3'
|
||||
else:
|
||||
this_play = await singles(session, interaction, this_play, '*')
|
||||
|
||||
if '#' in hit_result:
|
||||
logger.info(f'Checking if the # result becomes a hit')
|
||||
if this_play.ai_is_batting:
|
||||
if (position in ['1B', '3B', 'P', 'C'] and def_alignment.corners_in) or (position in ['1B, ''2B', '3B', 'SS', 'P', 'C'] and def_alignment.infield_in):
|
||||
hit_result = 'SI2'
|
||||
|
||||
if hit_result not in ['SI1', 'SI2', 'DO2', 'DO3', 'TR'] and error_result is None:
|
||||
elif this_play.on_base_code > 0:
|
||||
is_holding = False
|
||||
|
||||
if not playing_in:
|
||||
if position == '1B' and this_play.on_first is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_second.card.player.name} held at first base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif position == '3B' and this_play.on_second is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_second.card.player.name} held at second base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif position == '2B' and (this_play.on_first is not None or this_play.on_second is not None) and (this_play.batter.card.batterscouting.battingcard.hand == 'R' or (this_play.batter.card.batterscouting.battingcard.hand == 'S' and this_play.pitcher.card.pitcherscouting.pitchingcard.hand == 'L')):
|
||||
if this_play.on_second is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_second.card.player.name} held at second base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif this_play.on_first is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_first.card.player.name} held at first base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif position == 'SS' and (this_play.on_first is not None or this_play.on_second is not None) and (this_play.batter.card.batterscouting.battingcard.hand == 'L' or (this_play.batter.card.batterscouting.battingcard.hand == 'S' and this_play.pitcher.card.pitcherscouting.pitchingcard.hand == 'R')):
|
||||
if this_play.on_second is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_second.card.player.name} held at second base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif this_play.on_first is not None:
|
||||
is_holding = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {this_play.on_first.card.player.name} held at first base?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
if is_holding or playing_in:
|
||||
hit_result = 'SI2'
|
||||
|
||||
if is_rare_play:
|
||||
logger.info(f'Is rare play')
|
||||
if hit_result == 'SI1':
|
||||
this_play = await singles(session, interaction, this_play, '*')
|
||||
if this_play.on_first is None:
|
||||
this_play.error = 1
|
||||
this_play.batter_final = 2
|
||||
|
||||
elif hit_result == 'SI2':
|
||||
this_play = await singles(session, interaction, this_play, '**')
|
||||
this_play.batter_final = None
|
||||
this_play.outs = 1
|
||||
|
||||
elif 'DO' in hit_result:
|
||||
this_play = await doubles(session, interaction, this_play, '***')
|
||||
this_play.batter_final = None
|
||||
this_play.outs = 1
|
||||
|
||||
elif hit_result == 'TR':
|
||||
this_play = await triples(session, interaction, this_play)
|
||||
this_play.batter_final = 4
|
||||
this_play.run = 1
|
||||
this_play.error = 1
|
||||
|
||||
elif hit_result == 'PO':
|
||||
this_play = advance_runners(session, this_play, 1, earned_bases=0)
|
||||
this_play.ab, this_play.error, this_play.batter_final = 1, 1, 1
|
||||
|
||||
elif hit_result == 'FO':
|
||||
this_play = advance_runners(session, this_play, 1, is_error=True, only_forced=True)
|
||||
this_play.ab, this_play.error, this_play.batter_final = 1, 1, 1
|
||||
|
||||
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)
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'A', position=this_play.check_pos, defender_is_in=defender_is_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)
|
||||
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, 'B', position=this_play.check_pos, defender_is_in=defender_is_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)
|
||||
|
||||
elif hit_result == 'SPD':
|
||||
this_play = singles(session, interaction, this_play, '*')
|
||||
|
||||
elif hit_result == 'F1':
|
||||
this_play.outs = 1
|
||||
this_play.ab = 1 if this_play.on_third is None else 0
|
||||
if this_play.on_base_code > 0 and this_play.starting_outs < 2:
|
||||
this_play = advance_runners(session, this_play, 1)
|
||||
|
||||
if this_play.on_second is not None:
|
||||
this_play.on_second_final = 4
|
||||
log_run_scored(session, this_play.on_second, this_play, is_earned=False)
|
||||
|
||||
elif this_play.on_first is not None:
|
||||
this_play.on_first_final = 3
|
||||
|
||||
elif hit_result == 'F2':
|
||||
this_play.outs = 1
|
||||
this_play.ab = 1 if this_play.on_third is None else 0
|
||||
|
||||
if this_play.on_base_code > 0 and this_play.starting_outs < 2:
|
||||
this_play.on_third_final = None
|
||||
this_play.outs = 2
|
||||
|
||||
else:
|
||||
this_play.outs = 1
|
||||
this_play.ab = 1
|
||||
|
||||
if this_play.on_third:
|
||||
this_play.outs = 2
|
||||
this_play.on_third_final = None
|
||||
|
||||
elif this_play.on_second:
|
||||
this_play.outs = 2
|
||||
this_play.on_second_final = None
|
||||
|
||||
elif this_play.on_first:
|
||||
this_play.outs = 2
|
||||
this_play.on_first_final = None
|
||||
|
||||
elif hit_result not in ['SI1', 'SI2', 'DO2', 'DO3', 'TR'] and error_result is None:
|
||||
logger.info(f'Not a hit, not an error')
|
||||
if this_play.on_base_code == 0:
|
||||
this_play.ab, this_play.outs = 1, 1
|
||||
this_play = await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
# TODO: Continue working through results
|
||||
# elif this_play
|
||||
else:
|
||||
to_mif = position in ['2B', 'SS']
|
||||
to_right_side = position in ['1B', '2B']
|
||||
|
||||
if 'G3' in hit_result:
|
||||
if this_play.on_base_code == 2 and not defender_is_in:
|
||||
this_play = await gb_result(session, interaction, this_play, 12)
|
||||
|
||||
elif defender_is_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]:
|
||||
this_play = await gb_decide(session, interaction=interaction, this_play=this_play)
|
||||
|
||||
elif defender_is_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:
|
||||
this_play = await gb_result(session, interaction, this_play, 11)
|
||||
|
||||
elif not defender_is_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]:
|
||||
this_play = await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
elif this_play.on_base_code == 2:
|
||||
this_play = await gb_result(session, interaction, this_play, 12)
|
||||
|
||||
else:
|
||||
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:
|
||||
this_play = await gb_result(session, interaction, this_play, 10)
|
||||
|
||||
elif not defender_is_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]:
|
||||
this_play = await gb_result(session, interaction, this_play, 3)
|
||||
|
||||
elif defender_is_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:
|
||||
this_play = await gb_result(session, interaction, this_play, 12)
|
||||
|
||||
else:
|
||||
this_play = await gb_result(session, interaction, this_play, 2)
|
||||
|
||||
elif 'F1' in hit_result:
|
||||
this_play = await flyballs(session, interaction, this_play, 'a')
|
||||
|
||||
elif 'F2' in hit_result:
|
||||
this_play = await flyballs(session, interaction, this_play, 'b')
|
||||
|
||||
elif 'F3' in hit_result:
|
||||
this_play = await flyballs(session, interaction, this_play, 'c')
|
||||
|
||||
# FO and PO
|
||||
else:
|
||||
this_play.ab, this_play.outs = 1, 1
|
||||
this_play = advance_runners(session, this_play, 0)
|
||||
|
||||
elif hit_result not in ['SI1', 'SI2', 'DO2', 'DO3', 'TR'] and error_result is not None:
|
||||
logger.info(f'Not a hit, {error_result}-base error')
|
||||
this_play = advance_runners(session, this_play, error_result, earned_bases=0)
|
||||
this_play.ab, this_play.error, this_play.batter_final = 1, 1, error_result
|
||||
|
||||
else:
|
||||
logger.info(f'Hit result: {hit_result}, Error: {error_result}')
|
||||
if hit_result == 'SI1' and error_result is None:
|
||||
this_play = await singles(session, interaction, this_play, '*')
|
||||
elif hit_result == 'SI1':
|
||||
this_play.ab, this_play.hit, this_play.error, this_play.batter_final = 1, 1, 1, 2
|
||||
this_play = advance_runners(session, this_play, num_bases=error_result + 1, earned_bases=1)
|
||||
|
||||
elif hit_result == 'SI2' and error_result is None:
|
||||
this_play = await singles(session, interaction, this_play, '**')
|
||||
elif hit_result == 'SI2':
|
||||
this_play.ab, this_play.hit, this_play.error = 1, 1, 1
|
||||
if error_result > 1:
|
||||
num_bases = 3
|
||||
this_play.batter_final = 3
|
||||
else:
|
||||
num_bases = 2
|
||||
this_play.batter_final = 2
|
||||
this_play = advance_runners(session, this_play, num_bases=num_bases, earned_bases=2)
|
||||
|
||||
elif hit_result == 'DO2' and error_result is None:
|
||||
this_play = await doubles(session, interaction, this_play, '**')
|
||||
elif hit_result == 'DO2':
|
||||
this_play.ab, this_play.hit, this_play.error, this_play.double = 1, 1, 1, 1
|
||||
num_bases = 3
|
||||
|
||||
if error_result == 3:
|
||||
this_play.batter_final = 4
|
||||
else:
|
||||
this_play.batter_final = 3
|
||||
|
||||
this_play = advance_runners(session, this_play, num_bases=num_bases, earned_bases=2)
|
||||
|
||||
elif hit_result == 'DO3' and error_result is None:
|
||||
this_play = await doubles(session, interaction, this_play, '***')
|
||||
elif hit_result == 'DO3':
|
||||
this_play.ab, this_play.hit, this_play.error, this_play.double = 1, 1, 1, 1
|
||||
|
||||
if error_result == 1:
|
||||
this_play.batter_final = 3
|
||||
else:
|
||||
this_play.batter_final = 4
|
||||
|
||||
this_play = advance_runners(session, this_play, num_bases=4, earned_bases=2)
|
||||
|
||||
elif hit_result == 'TR' and error_result is None:
|
||||
this_play = await triples(session, interaction, this_play)
|
||||
else:
|
||||
this_play.ab, this_play.hit, this_play.error, this_play.triple = 1, 1, 1, 1
|
||||
this_play = advance_runners(session, this_play, num_bases=4, earned_bases=3)
|
||||
|
||||
session.add(this_play)
|
||||
session.commit()
|
||||
@ -1672,6 +1983,7 @@ async def xchecks(session: Session, interaction: discord.Interaction, this_play:
|
||||
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()
|
||||
|
||||
@ -2197,10 +2509,84 @@ async def manual_end_game(session: Session, interaction: discord.Interaction, th
|
||||
await complete_game(session, interaction, current_play)
|
||||
|
||||
|
||||
async def gb_result(session: Session, interaction: discord.Interaction, this_play: Play, groundball_result: int, to_mif: bool = None, to_right_side: bool = None):
|
||||
async def groundballs(session: Session, interaction: discord.Interaction, this_play: Play, groundball_letter: Literal['a', 'b', 'c']):
|
||||
if this_play.on_base_code == 2 and groundball_letter in ['a', 'b']:
|
||||
to_right_side = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was that ball hit to either 1B or 2B?',
|
||||
label_type='yes'
|
||||
)
|
||||
this_play = gb_result_6(session, this_play, to_right_side)
|
||||
|
||||
elif this_play.on_base_code in [3, 6] and groundball_letter in ['a', 'b']:
|
||||
to_mif = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was that ball hit to either 2B or SS?',
|
||||
label_type='yes'
|
||||
)
|
||||
this_play = gb_result_5(session, this_play, to_mif)
|
||||
|
||||
else:
|
||||
this_play = await gb_letter(session, interaction, this_play, groundball_letter.upper(), 'None', False)
|
||||
|
||||
session.add(this_play)
|
||||
session.commit()
|
||||
|
||||
session.refresh(this_play)
|
||||
return this_play
|
||||
|
||||
|
||||
async def gb_letter(session: Session, interaction: discord.Interaction, this_play: Play, groundball_letter: Literal['A', 'B', 'C'], position: str, defender_is_in: bool):
|
||||
"""
|
||||
Commits this_play
|
||||
"""
|
||||
if not defender_is_in:
|
||||
if this_play.on_base_code == 0:
|
||||
return await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
elif groundball_letter == 'C':
|
||||
return await gb_result(session, interaction, this_play, 3)
|
||||
|
||||
elif groundball_letter == 'A' and this_play.on_base_code in [1, 4, 5, 7]:
|
||||
return await gb_result(session, interaction, this_play, 2)
|
||||
|
||||
elif groundball_letter == 'B' and this_play.on_base_code in [1, 4, 5, 7]:
|
||||
return await gb_result(session, interaction, this_play, 4)
|
||||
|
||||
elif this_play.on_base_code in [3, 6]:
|
||||
return await gb_result(session, interaction, this_play, 5, to_mif=position in ['2B', 'SS'])
|
||||
|
||||
else:
|
||||
return await gb_result(session, interaction, this_play, 6, to_right_side=position in ['1B', '2B'])
|
||||
|
||||
else:
|
||||
if groundball_letter == 'A' and this_play.on_base_code == 7:
|
||||
return await gb_result(session, interaction, this_play, 10)
|
||||
|
||||
elif groundball_letter == 'B' and this_play.on_base_code == 5:
|
||||
return await gb_result(session, interaction, this_play, 9)
|
||||
|
||||
elif this_play.on_base_code == 7:
|
||||
return await gb_result(session, interaction, this_play, 11)
|
||||
|
||||
elif groundball_letter == 'A':
|
||||
return await gb_result(session, interaction, this_play, 7)
|
||||
|
||||
elif groundball_letter == 'B':
|
||||
return await gb_result(session, interaction, this_play, 1)
|
||||
|
||||
else:
|
||||
return await gb_result(session, interaction, this_play, 8)
|
||||
|
||||
|
||||
async def gb_result(session: Session, interaction: discord.Interaction, this_play: Play, groundball_result: int, to_mif: bool = None, to_right_side: bool = None):
|
||||
"""
|
||||
Commits this_play
|
||||
|
||||
Result 5 requires to_mif
|
||||
Result 6 requires to_right_side
|
||||
"""
|
||||
logger.info(f'Starting a groundball result: GB #{groundball_result}, to_mif: {to_mif}, to_right_side: {to_right_side}')
|
||||
if groundball_result == 1:
|
||||
this_play = gb_result_1(session, this_play)
|
||||
elif groundball_result == 2:
|
||||
@ -2224,7 +2610,7 @@ async def gb_result(session: Session, interaction: discord.Interaction, this_pla
|
||||
elif groundball_result == 11:
|
||||
this_play = gb_result_11(session, this_play)
|
||||
elif groundball_result == 12:
|
||||
this_play = gb_result_12(session, this_play, interaction)
|
||||
this_play = await gb_result_12(session, this_play, interaction)
|
||||
elif groundball_result == 13:
|
||||
this_play = gb_result_13(session, this_play)
|
||||
|
||||
@ -2238,7 +2624,7 @@ async def gb_result(session: Session, interaction: discord.Interaction, this_pla
|
||||
def gb_result_1(session: Session, this_play: Play):
|
||||
logger.info(f'GB 1')
|
||||
this_play = advance_runners(session, this_play, 0)
|
||||
this_play.ab, this_play.ab, this_play.outs = 1, 1, 1
|
||||
this_play.ab, this_play.outs = 1, 1
|
||||
|
||||
return this_play
|
||||
|
||||
@ -2247,7 +2633,7 @@ def gb_result_2(session: Session, this_play: Play):
|
||||
logger.info(f'GB 2')
|
||||
num_outs = 2 if this_play.starting_outs <= 1 else 1
|
||||
|
||||
this_play.ab, this_play.outs = 1, 1
|
||||
this_play.ab, this_play.outs = 1, num_outs
|
||||
this_play.on_first_final = None
|
||||
|
||||
if num_outs + this_play.starting_outs < 3:
|
||||
@ -2275,7 +2661,7 @@ def gb_result_4(session: Session, this_play: Play):
|
||||
this_play = advance_runners(session, this_play, 1)
|
||||
|
||||
this_play.ab, this_play.outs = 1, 1
|
||||
this_play.on_first_final = None
|
||||
this_play.on_first_final = 1
|
||||
|
||||
return this_play
|
||||
|
||||
@ -2345,14 +2731,17 @@ def gb_result_11(session: Session, this_play: Play):
|
||||
async def gb_decide(session: Session, this_play: Play, interaction: discord.Interaction):
|
||||
logger.info(f'GB Decide')
|
||||
runner = this_play.on_third if this_play.on_third is not None else this_play.on_second
|
||||
logger.info(f'runner: {runner}')
|
||||
pos_rating = await get_position(session, this_play.defender.card, this_play.check_pos)
|
||||
safe_range = runner.card.batterscouting.battingcard.running - 4 + pos_rating.range
|
||||
advance_base = 4 if this_play.on_third is not None else 3
|
||||
logger.info(f'pos_rating: {pos_rating}\nsafe_range: {safe_range}\nadvance_base: {advance_base}')
|
||||
|
||||
if this_play.game.ai_team is not None and this_play.ai_is_batting:
|
||||
run_resp = this_play.managerai.gb_decide_run(session, this_play.game)
|
||||
|
||||
if this_play.on_second is None:
|
||||
log_exception(InvalidResultException, 'Cannot run GB Decide without a runner on second.')
|
||||
if this_play.on_second is None and this_play.on_third is None:
|
||||
log_exception(InvalidResultException, 'Cannot run GB Decide without a runner on base.')
|
||||
|
||||
if safe_range >= run_resp.min_safe:
|
||||
is_lead_running = True
|
||||
@ -2362,7 +2751,7 @@ async def gb_decide(session: Session, this_play: Play, interaction: discord.Inte
|
||||
else:
|
||||
is_lead_running = await ask_confirm(
|
||||
interaction,
|
||||
f'Is {runner.card.player.name} attempting to advance to third?',
|
||||
f'Is {runner.card.player.name} attempting to advance {TO_BASE[advance_base]} with a 1-{safe_range} safe range?',
|
||||
label_type='yes',
|
||||
delete_question=False
|
||||
)
|
||||
@ -2381,7 +2770,7 @@ async def gb_decide(session: Session, this_play: Play, interaction: discord.Inte
|
||||
)
|
||||
throw_for_lead = throw_resp.at_lead_runner
|
||||
await interaction.channel.send(
|
||||
content=f'**{this_play.defender.player.name}** is {"not" if not throw_for_lead else ""} throwing for {runner.player.name}{"!" if throw_for_lead else "."}'
|
||||
content=f'**{this_play.defender.player.name}** is {"not " if not throw_for_lead else ""}throwing for {runner.player.name}{"!" if throw_for_lead else "."}'
|
||||
)
|
||||
else:
|
||||
throw_for_lead = await ask_confirm(
|
||||
|
||||
24
dice.py
24
dice.py
@ -32,7 +32,7 @@ class JumpRoll(DiceRoll):
|
||||
|
||||
class FieldingRoll(DiceRoll):
|
||||
d_six_three: int | None = None
|
||||
hit_result: Literal['SI1', 'SI2', 'DO2', 'DO3', 'TR', 'G1', 'G2', 'G3', 'G1#', 'G2#', 'G3#', 'F1', 'F2', 'F3', 'SPD'] | None = None
|
||||
hit_result: Literal['SI1', 'SI2', 'DO2', 'DO3', 'TR', 'G1', 'G2', 'G3', 'G1#', 'G2#', 'G3#', 'F1', 'F2', 'F3', 'SPD', 'PO', 'FO'] | None = None
|
||||
error_result: Literal[1, 2, 3] | None = None
|
||||
|
||||
|
||||
@ -817,6 +817,9 @@ def sa_fielding_roll(this_team: Team, this_play: Play, pos_code: str, def_rating
|
||||
d_twenty = random.randint(1, 20)
|
||||
)
|
||||
error_dice = this_roll.d_six_one + this_roll.d_six_two + this_roll.d_six_three
|
||||
this_roll.roll_message = f'```md\n' \
|
||||
f'# {str(this_roll.d_twenty)},{str(this_roll.d_six_one + this_roll.d_six_two + this_roll.d_six_three)}\n' \
|
||||
f'Details:[1d20;3d6 ({this_roll.d_twenty} - {this_roll.d_six_one} {this_roll.d_six_two} {this_roll.d_six_three})]```'
|
||||
|
||||
if pos_code in ['1B', '2B', '3B', 'SS']:
|
||||
x_chart = 'https://sombaseball.ddns.net/static/images/season04/range-infield.png'
|
||||
@ -1632,7 +1635,7 @@ def sa_fielding_roll(this_team: Team, this_play: Play, pos_code: str, def_rating
|
||||
elif def_rating.range == 3:
|
||||
this_roll.hit_result = 'SI2'
|
||||
elif def_rating.range == 4:
|
||||
this_roll.hit_result = 'DO2'
|
||||
this_roll.hit_result = 'SI2'
|
||||
else:
|
||||
this_roll.hit_result = 'DO2'
|
||||
|
||||
@ -2720,17 +2723,19 @@ def sa_fielding_roll(this_team: Team, this_play: Play, pos_code: str, def_rating
|
||||
)
|
||||
reference_string = f'[Range Chart]({x_chart}) / [Error Chart]({error_chart}) / [Result Reference]({symbol_link})'
|
||||
chart_embed.add_field(name='References', value=reference_string, inline=False)
|
||||
|
||||
this_roll.embeds = [roll_embed, chart_embed]
|
||||
|
||||
error1_embed, error2_embed = None, None
|
||||
if error_note1:
|
||||
error1_embed = get_dice_embed(this_team)
|
||||
error1_embed.add_field(name='Error Results', value=error_note1)
|
||||
this_roll.embeds.append(error1_embed)
|
||||
if error_note2:
|
||||
error2_embed = get_dice_embed(this_team)
|
||||
error2_embed.add_field(name='Error Results', value=error_note2)
|
||||
|
||||
this_roll.embeds = [roll_embed, chart_embed, error1_embed, error2_embed]
|
||||
logger.info(f'Game {this_play.game.id} | Team {this_team.id} ({this_team.abbrev}): {this_roll.roll_message}')
|
||||
this_roll.embeds.append(error1_embed)
|
||||
|
||||
logger.info(f'Game {this_play.game.id} | Team {this_team.id} ({this_team.abbrev}) Roll Message: {this_roll.roll_message}')
|
||||
return this_roll
|
||||
|
||||
|
||||
@ -2778,21 +2783,20 @@ def ab_roll(this_team: Team, this_game: Game, allow_chaos: bool = True) -> AbRol
|
||||
|
||||
if allow_chaos:
|
||||
if d_twenty == 1:
|
||||
logger.info(f'Game {this_game.id} - Wild Pitch Check')
|
||||
flag = 'wild pitch'
|
||||
elif d_twenty == 2:
|
||||
if random.randint(1, 2) == 1:
|
||||
logger.info(f'Game {this_game.id} - Balk Check')
|
||||
flag = 'balk'
|
||||
else:
|
||||
logger.info(f'Game {this_game.id} - Passed Ball Check')
|
||||
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,
|
||||
|
||||
@ -658,38 +658,55 @@ class ManagerAi(ManagerAiBase, table=True):
|
||||
|
||||
ai_rd = this_play.ai_run_diff
|
||||
aggression = self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5
|
||||
pitcher_hold = this_play.pitcher.card.pitcherscouting.pitchingcard.hold
|
||||
|
||||
catcher_defense = session.exec(select(PositionRating).where(PositionRating.player_id == this_play.catcher.player_id, PositionRating.position == 'C', PositionRating.variant == this_play.catcher.card.variant)).one()
|
||||
catcher_hold = catcher_defense.arm
|
||||
battery_hold = pitcher_hold + catcher_hold
|
||||
|
||||
if self.starting_outs == 2 and self.on_base_code > 0:
|
||||
if self.on_base_code == 1:
|
||||
if this_play.starting_outs == 2 and this_play.on_base_code > 0:
|
||||
if this_play.on_base_code == 1:
|
||||
this_resp.hold_first = True
|
||||
elif self.on_base_code == 2:
|
||||
this_resp.ai_note += f'- hold {this_play.on_first.player.name} on 1st\n'
|
||||
elif this_play.on_base_code == 2:
|
||||
this_resp.hold_second = True
|
||||
elif self.on_base_code in [4, 5, 7]:
|
||||
this_resp.ai_note += f'- hold {this_play.on_second.player.name} on 2nd\n'
|
||||
elif this_play.on_base_code in [4, 5, 7]:
|
||||
this_resp.hold_first = True
|
||||
this_resp.hold_second = True
|
||||
this_resp.ai_note += f'- hold {this_play.on_first.player.name} on 1st\n- hold {this_play.on_second.player.name} on 2nd\n'
|
||||
# elif self.on_base_code == 5:
|
||||
# ai_note += f'- hold the runner on first\n'
|
||||
elif self.on_base_code == 6:
|
||||
ai_note += f'- hold {self.on_second.player.name} on 2nd\n'
|
||||
elif self.on_base_code in [1, 5]:
|
||||
runner = self.on_first.player
|
||||
if self.on_first.card.batterscouting.battingcard.steal_auto:
|
||||
ai_note += f'- hold {runner.name} on 1st\n'
|
||||
elif self.on_base_code in [2, 4]:
|
||||
if self.on_second.card.batterscouting.battingcard.steal_low + max(self.pitcher.card.pitcherscouting.pitchingcard.hold, 5) >= 14:
|
||||
ai_note += f'- hold {self.on_second.player.name} on 2nd\n'
|
||||
# this_resp.ai_note += f'- hold the runner on first\n'
|
||||
elif this_play.on_base_code == 6:
|
||||
this_resp.hold_second = True
|
||||
this_resp.ai_note += f'- hold {this_play.on_second.player.name} on 2nd\n'
|
||||
elif this_play.on_base_code in [1, 5]:
|
||||
runner = this_play.on_first.player
|
||||
if this_play.on_first.card.batterscouting.battingcard.steal_auto and ((this_play.on_first.card.batterscouting.battingcard.steal_high + battery_hold) >= (12 - aggression)):
|
||||
this_resp.hold_first = True
|
||||
this_resp.ai_note += f'- hold {runner.name} on 1st\n'
|
||||
elif this_play.on_base_code in [2, 4]:
|
||||
if (this_play.on_second.card.batterscouting.battingcard.steal_low + max(battery_hold, 5)) >= (14 - aggression):
|
||||
this_resp.hold_second = True
|
||||
this_resp.ai_note += f'- hold {this_play.on_second.player.name} on 2nd\n'
|
||||
|
||||
# Defensive Alignment
|
||||
if self.on_third and self.starting_outs < 2:
|
||||
if self.could_walkoff:
|
||||
ai_note += f'- play the outfield and infield in'
|
||||
elif abs(self.away_score - self.home_score) <= 3:
|
||||
ai_note += f'- play the whole infield in\n'
|
||||
if this_play.on_third and this_play.starting_outs < 2:
|
||||
if this_play.could_walkoff:
|
||||
this_resp.outfield_in = True
|
||||
this_resp.infield_in = True
|
||||
this_resp.ai_note += f'- play the outfield and infield in'
|
||||
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'
|
||||
else:
|
||||
ai_note += f'- play the corners in\n'
|
||||
this_resp.corners_in = True
|
||||
this_resp.ai_note += f'- play the corners in\n'
|
||||
|
||||
if len(ai_note) == 0 and self.on_base_code > 0:
|
||||
ai_note += f'- play straight up\n'
|
||||
if len(this_resp.ai_note) == 0 and this_play.on_base_code > 0:
|
||||
this_resp.ai_note += f'- play straight up\n'
|
||||
|
||||
return this_resp
|
||||
|
||||
def gb_decide_run(self, session: Session, this_game: Game) -> RunResponse:
|
||||
this_resp = RunResponse()
|
||||
@ -881,21 +898,21 @@ class BattingRatings(BattingRatingsBase, table=True):
|
||||
|
||||
class BatterScoutingBase(SQLModel):
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
battingcard_id: int | None = Field(default=None, foreign_key='battingcard.id')
|
||||
ratings_vl_id: int | None = Field(default=None, foreign_key='battingratings.id')
|
||||
ratings_vr_id: int | None = Field(default=None, foreign_key='battingratings.id')
|
||||
battingcard_id: int | None = Field(default=None, foreign_key='battingcard.id', ondelete='CASCADE')
|
||||
ratings_vl_id: int | None = Field(default=None, foreign_key='battingratings.id', ondelete='CASCADE')
|
||||
ratings_vr_id: int | None = Field(default=None, foreign_key='battingratings.id', ondelete='CASCADE')
|
||||
created: datetime.datetime = Field(default_factory=datetime.datetime.now, nullable=True)
|
||||
|
||||
|
||||
class BatterScouting(BatterScoutingBase, table=True):
|
||||
battingcard: BattingCard = Relationship() #back_populates='batterscouting')
|
||||
ratings_vl: BattingRatings = Relationship(
|
||||
sa_relationship_kwargs=dict(foreign_keys="[BatterScouting.ratings_vl_id]")
|
||||
sa_relationship_kwargs=dict(foreign_keys="[BatterScouting.ratings_vl_id]",single_parent=True), cascade_delete=True
|
||||
)
|
||||
ratings_vr: BattingRatings = Relationship(
|
||||
sa_relationship_kwargs=dict(foreign_keys="[BatterScouting.ratings_vr_id]")
|
||||
sa_relationship_kwargs=dict(foreign_keys="[BatterScouting.ratings_vr_id]",single_parent=True), cascade_delete=True
|
||||
)
|
||||
cards: list['Card'] = Relationship(back_populates='batterscouting', cascade_delete=True)
|
||||
cards: list['Card'] = Relationship(back_populates='batterscouting')
|
||||
|
||||
|
||||
class PitchingCardBase(SQLModel):
|
||||
@ -962,21 +979,21 @@ class PitchingRatings(PitchingRatingsBase, table=True):
|
||||
|
||||
class PitcherScoutingBase(SQLModel):
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
pitchingcard_id: int | None = Field(default=None, foreign_key='pitchingcard.id',)
|
||||
ratings_vl_id: int | None = Field(default=None, foreign_key='pitchingratings.id')
|
||||
ratings_vr_id: int | None = Field(default=None, foreign_key='pitchingratings.id')
|
||||
pitchingcard_id: int | None = Field(default=None, foreign_key='pitchingcard.id', ondelete='CASCADE')
|
||||
ratings_vl_id: int | None = Field(default=None, foreign_key='pitchingratings.id', ondelete='CASCADE')
|
||||
ratings_vr_id: int | None = Field(default=None, foreign_key='pitchingratings.id', ondelete='CASCADE')
|
||||
created: datetime.datetime = Field(default_factory=datetime.datetime.now, nullable=True)
|
||||
|
||||
|
||||
class PitcherScouting(PitcherScoutingBase, table=True):
|
||||
pitchingcard: PitchingCard = Relationship()
|
||||
ratings_vl: PitchingRatings = Relationship(
|
||||
sa_relationship_kwargs=dict(foreign_keys="[PitcherScouting.ratings_vl_id]")
|
||||
sa_relationship_kwargs=dict(foreign_keys="[PitcherScouting.ratings_vl_id]",single_parent=True), cascade_delete=True
|
||||
)
|
||||
ratings_vr: PitchingRatings = Relationship(
|
||||
sa_relationship_kwargs=dict(foreign_keys="[PitcherScouting.ratings_vr_id]")
|
||||
sa_relationship_kwargs=dict(foreign_keys="[PitcherScouting.ratings_vr_id]",single_parent=True), cascade_delete=True
|
||||
)
|
||||
cards: list['Card'] = Relationship(back_populates='pitcherscouting', cascade_delete=True)
|
||||
cards: list['Card'] = Relationship(back_populates='pitcherscouting')
|
||||
|
||||
|
||||
class CardBase(SQLModel):
|
||||
|
||||
@ -155,18 +155,35 @@ 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}')
|
||||
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()
|
||||
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'])
|
||||
|
||||
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()
|
||||
|
||||
# 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)
|
||||
@ -188,33 +205,45 @@ async def get_batter_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
session.commit()
|
||||
session.refresh(db_scouting)
|
||||
return db_scouting
|
||||
|
||||
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]
|
||||
)
|
||||
|
||||
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]
|
||||
)
|
||||
# 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
|
||||
# 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}')
|
||||
if not skip_cache and card.pitcherscouting is not None:
|
||||
this_scouting = session.get(PitcherScouting, card.pitcherscouting.id)
|
||||
|
||||
s_query = await db_get(f'pitchingcardratings/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.')
|
||||
|
||||
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()
|
||||
this_scouting = session.get(PitcherScouting, s_query['ratings'][0]['pitchingcard']['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(pitching_card: dict, ratings_vr: dict, ratings_vl: dict) -> PitcherScouting:
|
||||
valid_bc = PitchingCardBase.model_validate(pitching_card, from_attributes=True)
|
||||
db_bc = PitchingCard.model_validate(valid_bc)
|
||||
@ -236,17 +265,60 @@ async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache:
|
||||
session.refresh(db_scouting)
|
||||
return db_scouting
|
||||
|
||||
s_query = await db_get(f'pitchingcardratings/player/{card.player.id}', none_okay=False)
|
||||
if s_query['count'] == 2:
|
||||
scouting = cache_scouting(
|
||||
pitching_card=s_query['ratings'][0]['pitchingcard'],
|
||||
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]
|
||||
)
|
||||
pos_rating = await get_position(session, card, 'P')
|
||||
return scouting
|
||||
scouting = cache_scouting(
|
||||
pitching_card=s_query['ratings'][0]['pitchingcard'],
|
||||
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]
|
||||
)
|
||||
pos_rating = await get_position(session, card, 'P')
|
||||
return scouting
|
||||
|
||||
return None
|
||||
# if not skip_cache and card.pitcherscouting is not None:
|
||||
# this_scouting = session.get(PitcherScouting, card.pitcherscouting.id)
|
||||
# # s_query = session.exec(select(PitcherScouting).where(PitcherScouting.pitchingcard_id == card.))
|
||||
|
||||
# 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(pitching_card: dict, ratings_vr: dict, ratings_vl: dict) -> PitcherScouting:
|
||||
# valid_bc = PitchingCardBase.model_validate(pitching_card, from_attributes=True)
|
||||
# db_bc = PitchingCard.model_validate(valid_bc)
|
||||
|
||||
# valid_vl = PitchingRatingsBase.model_validate(ratings_vl, from_attributes=True)
|
||||
# db_vl = PitchingRatings.model_validate(valid_vl)
|
||||
|
||||
# valid_vr = PitchingRatingsBase.model_validate(ratings_vr, from_attributes=True)
|
||||
# db_vr = PitchingRatings.model_validate(valid_vr)
|
||||
|
||||
# db_scouting = PitcherScouting(
|
||||
# pitchingcard=db_bc,
|
||||
# ratings_vl=db_vl,
|
||||
# ratings_vr=db_vr
|
||||
# )
|
||||
|
||||
# session.add(db_scouting)
|
||||
# session.commit()
|
||||
# session.refresh(db_scouting)
|
||||
# return db_scouting
|
||||
|
||||
# s_query = await db_get(f'pitchingcardratings/player/{card.player.id}', none_okay=False)
|
||||
# if s_query['count'] == 2:
|
||||
# scouting = cache_scouting(
|
||||
# pitching_card=s_query['ratings'][0]['pitchingcard'],
|
||||
# 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]
|
||||
# )
|
||||
# pos_rating = await get_position(session, card, 'P')
|
||||
# return scouting
|
||||
|
||||
# return None
|
||||
|
||||
|
||||
# async def get_position_rating_or_none(session: Session, card: Card, position: str, skip_cache: bool = False) -> PositionRating | None:
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import pydantic
|
||||
|
||||
|
||||
class RunResponse(pydantic.BaseModel):
|
||||
class AiResponse(pydantic.BaseModel):
|
||||
ai_note: str = ''
|
||||
|
||||
|
||||
class RunResponse(AiResponse):
|
||||
min_safe: int | None = None
|
||||
|
||||
|
||||
@ -20,7 +24,7 @@ class UncappedRunResponse(RunResponse):
|
||||
trail_min_safe_delta: int = 0
|
||||
|
||||
|
||||
class ThrowResponse(pydantic.BaseModel):
|
||||
class ThrowResponse(AiResponse):
|
||||
cutoff: bool = False # Stops on True
|
||||
at_lead_runner: bool = True
|
||||
at_trail_runner: bool = False # Stops on False
|
||||
@ -28,10 +32,20 @@ class ThrowResponse(pydantic.BaseModel):
|
||||
trail_max_safe_delta: int = -6
|
||||
|
||||
|
||||
class DefenseResponse(pydantic.BaseModel):
|
||||
class DefenseResponse(AiResponse):
|
||||
hold_first: bool = False
|
||||
hold_second: bool = False
|
||||
hold_third: bool = False
|
||||
outfield_in: bool = False
|
||||
infield_in: bool = False
|
||||
corners_in: bool = False
|
||||
|
||||
def defender_in(self, position: str):
|
||||
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']:
|
||||
return True
|
||||
elif self.outfield_in and position in ['LF', 'CF', 'RF']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from sqlmodel import Session, select, func
|
||||
|
||||
from command_logic.logic_gameplay import advance_runners, doubles, get_obc, get_re24, get_wpa, complete_play, log_run_scored, strikeouts, steals
|
||||
from command_logic.logic_gameplay import advance_runners, doubles, gb_result_1, get_obc, get_re24, get_wpa, complete_play, log_run_scored, strikeouts, steals, xchecks
|
||||
from in_game.gameplay_models import Lineup, Play
|
||||
from tests.factory import session_fixture, Game
|
||||
|
||||
@ -22,7 +22,7 @@ def test_advance_runners(session: Session):
|
||||
assert play_2.on_second_id == play_1.batter_id
|
||||
|
||||
play_2.pa, play_2.ab, play_2.hit, play_2.batter_final = 1, 1, 1, 1
|
||||
advance_runners(session, play_2, 1)
|
||||
play_2 = advance_runners(session, play_2, 1)
|
||||
session.add(play_2)
|
||||
session.commit()
|
||||
|
||||
@ -35,6 +35,17 @@ def test_advance_runners(session: Session):
|
||||
assert play_3.on_second is None
|
||||
assert play_3.on_first is not None
|
||||
|
||||
play_3.pa, play_3.ab, play_3.hit, play_3.batter_final = 1, 1, 1, 2
|
||||
play_3 = advance_runners(session, play_3, 3, earned_bases=1)
|
||||
session.add(play_3)
|
||||
session.commit()
|
||||
|
||||
assert play_3.rbi == 1
|
||||
assert play_2.run == 1
|
||||
assert play_2.e_run == 0
|
||||
assert play_1.run == 1
|
||||
assert play_1.e_run == 1
|
||||
|
||||
|
||||
def test_get_obc():
|
||||
assert get_obc() == 0
|
||||
@ -207,4 +218,3 @@ async def test_stealing(session: Session):
|
||||
assert play_2.on_first_final == 2
|
||||
assert play_2.sb == 1
|
||||
assert play_2.runner == play_2.on_first
|
||||
|
||||
|
||||
348
tests/command_logic/test_logic_groundballs.py
Normal file
348
tests/command_logic/test_logic_groundballs.py
Normal file
@ -0,0 +1,348 @@
|
||||
import pytest
|
||||
from sqlmodel import Session, select, func
|
||||
|
||||
from command_logic.logic_gameplay import advance_runners, gb_result_10, gb_result_11, gb_result_13, gb_result_2, gb_result_3, gb_result_4, gb_result_5, gb_result_6, gb_result_7, gb_result_8, gb_result_9, singles, doubles, triples, gb_result_1, complete_play, log_run_scored, strikeouts, steals, undo_play, xchecks
|
||||
from in_game.gameplay_models import Lineup, Play
|
||||
from tests.factory import session_fixture, Game
|
||||
|
||||
|
||||
def test_groundball_1(session: Session):
|
||||
game_1 = session.get(Game, 2)
|
||||
play_1 = session.get(Play, 1)
|
||||
play_1.hit, play_1.batter_final = 1, 2
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_1(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.on_second == play_2.on_second
|
||||
assert play_2.batter_final == None
|
||||
|
||||
|
||||
async def test_groundball_2_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_2(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 0
|
||||
assert ending.on_base_code == 0
|
||||
|
||||
|
||||
async def test_groundball_2_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await doubles(session, None, play_1, '**')
|
||||
play_1.starting_outs = 0
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_2(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_third == play_2.on_second
|
||||
|
||||
|
||||
async def test_groundball_2_3(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1)
|
||||
play_1.starting_outs = 0
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_2(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 1
|
||||
|
||||
|
||||
async def test_groundball_3_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_3(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 2
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_3_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await doubles(session, None, play_1, '**')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_3(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_3_3(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1,)
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_3(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 1
|
||||
|
||||
|
||||
async def test_groundball_4_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_4(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 1
|
||||
assert ending.on_first == play_2.batter
|
||||
|
||||
|
||||
async def test_groundball_4_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '**')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3 = gb_result_4(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 1
|
||||
assert ending.on_first == play_2.batter
|
||||
assert ending.away_score == 1
|
||||
|
||||
|
||||
async def test_groundball_5_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1)
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_5(session, play_2, True)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 1
|
||||
|
||||
|
||||
async def test_groundball_5_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1)
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_5(session, play_2, False)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_6_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await doubles(session, None, play_1, '**')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_6(session, play_2, True)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
|
||||
|
||||
async def test_groundball_6_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await doubles(session, None, play_1, '**')
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_6(session, play_2, False)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 2
|
||||
|
||||
|
||||
async def test_groundball_7_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1)
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_7(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_7_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '**')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3 = gb_result_7(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 6
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_8_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await triples(session, None, play_1)
|
||||
play_2 = complete_play(session, play_1)
|
||||
|
||||
play_2 = gb_result_8(session, play_2)
|
||||
ending = complete_play(session, play_2)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_8_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '**')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3 = gb_result_8(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 6
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_9_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '**')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3 = gb_result_9(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 6
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_10_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
play_3 = await singles(session, None, play_3, '*')
|
||||
play_4 = complete_play(session, play_3)
|
||||
|
||||
play_4 = gb_result_10(session, play_4)
|
||||
ending = complete_play(session, play_4)
|
||||
|
||||
assert ending.starting_outs == 0
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_13_1_1(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3.check_pos == '3B'
|
||||
play_3 = gb_result_13(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 0
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_13_1_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1.starting_outs = 0
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3.check_pos = '3B'
|
||||
play_3 = gb_result_13(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 1
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_13_1_3(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1.starting_outs = 0
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3.check_pos == '1B'
|
||||
play_3 = gb_result_13(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 2
|
||||
assert ending.on_base_code == 3
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_13_2(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3.check_pos == 'C'
|
||||
play_3 = gb_result_13(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 0
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
async def test_groundball_13_3(session: Session):
|
||||
play_1 = session.get(Play, 2)
|
||||
play_1 = await singles(session, None, play_1, '*')
|
||||
play_2 = complete_play(session, play_1)
|
||||
play_2 = await singles(session, None, play_2, '*')
|
||||
play_3 = complete_play(session, play_2)
|
||||
|
||||
play_3.check_pos == '1B'
|
||||
play_3 = gb_result_13(session, play_3)
|
||||
ending = complete_play(session, play_3)
|
||||
|
||||
assert ending.starting_outs == 0
|
||||
assert ending.on_base_code == 0
|
||||
assert ending.away_score == 0
|
||||
|
||||
|
||||
@ -218,7 +218,9 @@ class ScorebugButtons(discord.ui.View):
|
||||
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)
|
||||
logger.info(f'this_roll: {this_roll}')
|
||||
if this_roll.is_chaos:
|
||||
logger.info('AB Roll Is Chaos')
|
||||
self.had_chaos = True
|
||||
else:
|
||||
button.disabled = True
|
||||
|
||||
Loading…
Reference in New Issue
Block a user