Add DTwentyRoll
Add /log lineout Add ManagerAi.tag_from_third()
This commit is contained in:
parent
1e9e79916f
commit
95ee071ef8
@ -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, 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, 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, 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
|
||||
@ -433,7 +433,7 @@ class Gameplay(commands.Cog):
|
||||
session,
|
||||
interaction,
|
||||
this_play,
|
||||
buffer_message='Double logged' if this_play.starting_outs + this_play.outs < 3 and ((this_play.on_second and flyball_type == 'b') or (this_play.on_third and flyball_type == '?b')) else None
|
||||
buffer_message='Double logged' if this_play.starting_outs + this_play.outs < 3 and ((this_play.on_second and flyball_type == 'b') or (this_play.on_third and flyball_type == 'b?')) else None
|
||||
)
|
||||
|
||||
@group_log.command(name='frame-pitch', description=f'Walk/strikeout split; determined by home plate umpire')
|
||||
@ -451,6 +451,16 @@ class Gameplay(commands.Cog):
|
||||
buffer_message='Frame check logged'
|
||||
)
|
||||
|
||||
@group_log.command(name='lineout', description='Lineouts: one out, ballpark, max outs')
|
||||
async def log_lineout(self, interaction: discord.Interaction, lineout_type: Literal['one-out', 'ballpark', 'max-outs']):
|
||||
with Session(engine) as session:
|
||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log lineout')
|
||||
|
||||
logger.info(f'log lineout - this_play: {this_play}')
|
||||
this_play = await lineouts(session, interaction, this_play, lineout_type)
|
||||
|
||||
await self.complete_and_post_play(session, interaction, this_play, buffer_message='Lineout logged' if this_play.on_base_code > 3 else None)
|
||||
|
||||
@group_log.command(name='single', description='Singles: *, **, ballpark, uncapped')
|
||||
async def log_single(
|
||||
self, interaction: discord.Interaction, single_type: Literal['*', '**', 'ballpark', 'uncapped']):
|
||||
|
||||
@ -10,7 +10,7 @@ from sqlalchemy import delete
|
||||
from typing import Literal
|
||||
|
||||
from api_calls import db_delete, db_get, db_post
|
||||
from dice import frame_plate_check, sa_fielding_roll
|
||||
from dice import d_twenty_roll, frame_plate_check, sa_fielding_roll
|
||||
from exceptions import *
|
||||
from helpers import DEFENSE_LITERAL, SBA_COLOR, get_channel
|
||||
from in_game.game_helpers import legal_check
|
||||
@ -870,94 +870,254 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_play
|
||||
|
||||
if this_play.starting_outs < 2 and this_play.on_second:
|
||||
logger.debug(f'calling of embed')
|
||||
await show_outfield_cards(session, interaction, this_play)
|
||||
this_of = await show_outfield_cards(session, interaction, this_play)
|
||||
of_rating = await get_position(session, this_of.card, this_of.position)
|
||||
of_mod = 0
|
||||
if this_of.position == 'LF':
|
||||
of_mod = -2
|
||||
elif this_of.position == 'RF':
|
||||
of_mod = 2
|
||||
logger.debug(f'done with of embed')
|
||||
|
||||
runner = this_play.on_second.player
|
||||
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
||||
runner_lineup = this_play.on_second
|
||||
runner = runner_lineup.player
|
||||
|
||||
max_safe = runner_lineup.card.batterscouting.battingcard.running + of_rating.arm + of_mod
|
||||
min_out = 20 + of_rating.arm + of_mod
|
||||
if (min_out >= 20 and max_safe >= 20) or min_out > 20:
|
||||
min_out = 21
|
||||
min_hold = max_safe + 1
|
||||
|
||||
safe_string = f'1{" - " if max_safe > 1 else ""}'
|
||||
if max_safe > 1:
|
||||
if max_safe <= 20:
|
||||
safe_string += f'{max_safe}'
|
||||
else:
|
||||
safe_string += f'20'
|
||||
|
||||
if min_out > 20:
|
||||
out_string = 'None'
|
||||
else:
|
||||
out_string = f'{min_out}{" - 20" if min_out < 20 else ""}'
|
||||
|
||||
hold_string = ''
|
||||
if max_safe != min_out:
|
||||
hold_string += f'{min_hold}'
|
||||
if min_out - 1 > min_hold:
|
||||
hold_string += f' - {min_out - 1}'
|
||||
|
||||
ranges_embed = this_of.team.embed
|
||||
ranges_embed.title = f'Tag Play'
|
||||
ranges_embed.description = f'{this_of.team.abbrev} {this_of.position} {this_of.card.player.name}\'s Throw vs {runner.name}'
|
||||
ranges_embed.add_field(name=f'{this_of.position} Arm', value=f'{"+" if of_rating.arm > 0 else ""}{of_rating.arm}')
|
||||
ranges_embed.add_field(name=f'Runner Speed', value=runner_lineup.card.batterscouting.battingcard.running)
|
||||
ranges_embed.add_field(name=f'{this_of.position} Mod', value=f'{of_mod}', inline=False)
|
||||
ranges_embed.add_field(name='Safe Range', value=safe_string)
|
||||
ranges_embed.add_field(name='Hold Range', value=hold_string)
|
||||
ranges_embed.add_field(name='Out Range', value=out_string)
|
||||
await interaction.channel.send(
|
||||
content=None,
|
||||
embed=ranges_embed
|
||||
)
|
||||
|
||||
if this_play.ai_is_batting:
|
||||
tag_resp = this_play.managerai.tag_from_second(session, this_game)
|
||||
q_text = f'{runner.name} will attempt to advance to third if the safe range is **{tag_resp.min_safe}+**, are they going?'
|
||||
else:
|
||||
q_text = f'Is {runner.name} attempting to tag up to third?'
|
||||
|
||||
question = await interaction.channel.send(
|
||||
content=q_text,
|
||||
view=view
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
await question.delete()
|
||||
|
||||
view = ButtonOptions(
|
||||
responders=[interaction.user], timeout=60,
|
||||
labels=['Tagged Up', 'Hold at 2nd', 'Out at 3rd', None, None]
|
||||
)
|
||||
question = await interaction.channel.send(
|
||||
f'What was the result of {runner.name} tagging from second?', view=view
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
await question.delete()
|
||||
if view.value == 'Tagged Up':
|
||||
this_play.on_second_final = 3
|
||||
elif view.value == 'Out at 3rd':
|
||||
num_outs += 1
|
||||
this_play.on_second_final = None
|
||||
this_play.outs = num_outs
|
||||
logger.info(f'tag_resp: {tag_resp}')
|
||||
tagging_from_second = tag_resp.min_safe >= max_safe
|
||||
if tagging_from_second:
|
||||
await interaction.channel.send(
|
||||
content=f'**{runner.name}** is tagging from second!'
|
||||
)
|
||||
else:
|
||||
await question.delete()
|
||||
await interaction.channel.send(
|
||||
content=f'**{runner.name}** is holding at second.'
|
||||
)
|
||||
else:
|
||||
await question.delete()
|
||||
tagging_from_second = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Is {runner.name} attempting to tag up from second?',
|
||||
label_type='yes',
|
||||
)
|
||||
|
||||
if tagging_from_second:
|
||||
this_roll = d_twenty_roll(this_play.pitcher.team, this_play.game)
|
||||
if min_out is not None and this_roll.d_twenty >= min_out:
|
||||
result = 'out'
|
||||
elif this_roll.d_twenty <= max_safe:
|
||||
result = 'safe'
|
||||
else:
|
||||
result = 'holds'
|
||||
|
||||
await interaction.channel.send(content=None, embeds=this_roll.embeds)
|
||||
|
||||
is_correct = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Looks like {runner.name} {"is" if result != 'holds' else ""} **{result.upper()}** at {"third" if result != 'holds' else "second"}! Is that correct?',
|
||||
label_type='yes',
|
||||
delete_question=False
|
||||
)
|
||||
|
||||
if not is_correct:
|
||||
view = ButtonOptions(
|
||||
responders=[interaction.user], timeout=60,
|
||||
labels=['Safe at 3rd', 'Hold at 2nd', 'Out at 3rd', None, None]
|
||||
)
|
||||
question = await interaction.channel.send(
|
||||
f'What was the result of {runner.name} tagging from second?', view=view
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
await question.delete()
|
||||
if view.value == 'Tagged Up':
|
||||
result = 'safe'
|
||||
elif view.value == 'Out at 3rd':
|
||||
result = 'out'
|
||||
else:
|
||||
result = 'holds'
|
||||
else:
|
||||
await question.delete()
|
||||
|
||||
if result == 'safe':
|
||||
this_play.on_second_final = 3
|
||||
elif result == 'out':
|
||||
num_outs += 1
|
||||
this_play.on_second_final = None
|
||||
this_play.outs = num_outs
|
||||
|
||||
elif flyball_type == 'b?':
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
this_play = advance_runners(session, this_play, 0)
|
||||
|
||||
if this_play.starting_outs < 2 and this_play.on_third:
|
||||
logger.debug(f'calling of embed')
|
||||
await show_outfield_cards(session, interaction, this_play)
|
||||
this_of = await show_outfield_cards(session, interaction, this_play)
|
||||
of_rating = await get_position(session, this_of.card, this_of.position)
|
||||
logger.debug(f'done with of embed')
|
||||
|
||||
runner = this_play.on_second.player
|
||||
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
||||
runner_lineup = this_play.on_third
|
||||
runner = runner_lineup.player
|
||||
|
||||
max_safe = runner_lineup.card.batterscouting.battingcard.running + of_rating.arm
|
||||
|
||||
safe_string = f'1{" - " if max_safe > 1 else ""}'
|
||||
if max_safe > 1:
|
||||
if max_safe <= 20:
|
||||
safe_string += f'{max_safe - 1}'
|
||||
else:
|
||||
safe_string += f'20'
|
||||
|
||||
if max_safe == 20:
|
||||
out_string = 'None'
|
||||
catcher_string = '20'
|
||||
elif max_safe > 20:
|
||||
out_string = 'None'
|
||||
catcher_string = 'None'
|
||||
elif max_safe == 19:
|
||||
out_string = 'None'
|
||||
catcher_string = '19 - 20'
|
||||
elif max_safe == 18:
|
||||
out_string = f'20'
|
||||
catcher_string = '18 - 19'
|
||||
else:
|
||||
out_string = f'{max_safe + 2} - 20'
|
||||
catcher_string = f'{max_safe} - {max_safe + 1}'
|
||||
|
||||
true_max_safe = max_safe - 1
|
||||
true_min_out = max_safe + 2
|
||||
|
||||
ranges_embed = this_play.batter.team.embed
|
||||
ranges_embed.title = f'Play at the Plate'
|
||||
ranges_embed.description = f'{runner.name} vs {this_of.card.player.name}\'s Throw'
|
||||
ranges_embed.add_field(name=f'{this_of.position} Arm', value=f'{"+" if of_rating.arm > 0 else ""}{of_rating.arm}')
|
||||
ranges_embed.add_field(name=f'Runner Speed', value=runner_lineup.card.batterscouting.battingcard.running)
|
||||
ranges_embed.add_field(name="", value="", inline=False)
|
||||
ranges_embed.add_field(name='Safe Range', value=safe_string)
|
||||
ranges_embed.add_field(name='Catcher Check', value=catcher_string)
|
||||
ranges_embed.add_field(name='Out Range', value=out_string)
|
||||
await interaction.channel.send(
|
||||
content=None,
|
||||
embed=ranges_embed
|
||||
)
|
||||
|
||||
if this_play.ai_is_batting:
|
||||
tag_resp = this_play.managerai.tag_from_second(session, this_game)
|
||||
q_text = f'{runner.name} will attempt to advance home if the safe range is **{tag_resp.min_safe}+**, are they going?'
|
||||
tag_resp = this_play.managerai.tag_from_third(session, this_game)
|
||||
logger.info(f'tag_resp: {tag_resp}')
|
||||
tagging_from_third = tag_resp.min_safe <= max_safe
|
||||
if tagging_from_third:
|
||||
await interaction.channel.send(
|
||||
content=f'**{runner.name}** is tagging from third!'
|
||||
)
|
||||
else:
|
||||
await interaction.channel.send(
|
||||
content=f'**{runner.name}** is holding at third.'
|
||||
)
|
||||
else:
|
||||
q_text = f'Is {runner.name} attempting to tag up and go home?'
|
||||
|
||||
question = await interaction.channel.send(
|
||||
content=q_text,
|
||||
view=view
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
await question.delete()
|
||||
|
||||
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
||||
question = await interaction.channel.send(
|
||||
f'Was {runner.name} thrown out?', view=view
|
||||
tagging_from_third = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Is {runner.name} attempting to tag up from third?',
|
||||
label_type='yes',
|
||||
)
|
||||
await view.wait()
|
||||
|
||||
if tagging_from_third:
|
||||
this_roll = d_twenty_roll(this_play.batter.team, this_play.game)
|
||||
if this_roll.d_twenty <= true_max_safe:
|
||||
result = 'safe'
|
||||
q_text = f'Looks like {runner.name} is SAFE at home!'
|
||||
out_at_home = False
|
||||
elif this_roll.d_twenty >= true_min_out:
|
||||
result = 'out'
|
||||
q_text = f'Looks like {runner.name} is OUT at home!'
|
||||
out_at_home = True
|
||||
else:
|
||||
result = 'catcher'
|
||||
q_text = f'Looks like this is a check for {this_play.catcher.player.name} to block the plate!'
|
||||
|
||||
await interaction.channel.send(content=None, embeds=this_roll.embeds)
|
||||
|
||||
if view.value:
|
||||
await question.delete()
|
||||
is_correct = await ask_confirm(
|
||||
interaction,
|
||||
question=f'{q_text} Is that correct?',
|
||||
label_type='yes',
|
||||
delete_question=False
|
||||
)
|
||||
|
||||
if not is_correct:
|
||||
out_at_home = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Was {runner.name} thrown out?',
|
||||
label_type='yes'
|
||||
)
|
||||
|
||||
elif result == 'catcher':
|
||||
catcher_rating = await get_position(session, this_play.catcher.card, 'C')
|
||||
this_roll = d_twenty_roll(this_play.catcher.team, this_play.game)
|
||||
|
||||
if catcher_rating.range == 1:
|
||||
safe_range = 3
|
||||
elif catcher_rating.range == 2:
|
||||
safe_range = 7
|
||||
elif catcher_rating.range == 3:
|
||||
safe_range = 11
|
||||
elif catcher_rating.range == 4:
|
||||
safe_range = 15
|
||||
elif catcher_rating.range == 5:
|
||||
safe_range = 19
|
||||
|
||||
out_at_home = True
|
||||
|
||||
if this_roll.d_twenty <= safe_range:
|
||||
out_at_home = False
|
||||
|
||||
if out_at_home:
|
||||
num_outs += 1
|
||||
this_play.on_third_final = 99
|
||||
this_play.on_third_final = None
|
||||
this_play.outs = num_outs
|
||||
else:
|
||||
await question.delete()
|
||||
this_play.ab = 0
|
||||
this_play.rbi = 1
|
||||
this_play.on_third_final = 4
|
||||
log_run_scored(session, this_play.on_third, this_play)
|
||||
else:
|
||||
await question.delete()
|
||||
|
||||
elif flyball_type == 'c':
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
@ -970,6 +1130,100 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_play
|
||||
return this_play
|
||||
|
||||
|
||||
async def lineouts(session: Session, interaction: discord.Interaction, this_play: Play, lineout_type: Literal['one-out', 'ballpark', 'max-outs']) -> Play:
|
||||
"""
|
||||
Commits this_play
|
||||
"""
|
||||
num_outs = 1
|
||||
this_play.pa, this_play.ab, this_play.outs = 1, 1, 1
|
||||
this_play.bplo = 1 if lineout_type == 'ballpark' else 0
|
||||
this_play = advance_runners(session, this_play, num_bases=0)
|
||||
|
||||
if lineout_type == 'max-outs' and this_play.on_base_code > 0 and this_play.starting_outs < 2:
|
||||
logger.info(f'Lomax going in')
|
||||
if this_play.on_base_code <= 3 or this_play.starting_outs == 1:
|
||||
logger.info(f'Lead runner is out')
|
||||
this_play.outs = 2
|
||||
|
||||
if this_play.on_third is not None:
|
||||
this_play.on_third_final = None
|
||||
|
||||
elif this_play.on_second is not None:
|
||||
this_play.on_second_final = None
|
||||
|
||||
elif this_play.on_first is not None:
|
||||
this_play.on_first_final = None
|
||||
|
||||
else:
|
||||
logger.info(f'Potential triple play')
|
||||
this_roll = d_twenty_roll(this_play.pitcher.team, this_play.game)
|
||||
ranges_embed = this_play.pitcher.team.embed
|
||||
ranges_embed.title = f'Potential Triple Play'
|
||||
ranges_embed.description = f'{this_play.pitcher.team.lname}'
|
||||
ranges_embed.add_field(name=f'Double Play Range', value='1 - 13')
|
||||
ranges_embed.add_field(name=f'Triple Play Range', value='14 - 20')
|
||||
await interaction.edit_original_response(
|
||||
content=None,
|
||||
embeds=[ranges_embed, *this_roll.embeds]
|
||||
)
|
||||
|
||||
if this_roll.d_twenty > 13:
|
||||
logger.info(f'Roll of {this_roll.d_twenty} is a triple play!')
|
||||
num_outs = 3
|
||||
else:
|
||||
logger.info(f'Roll of {this_roll.d_twenty} is a double play!')
|
||||
num_outs = 2
|
||||
|
||||
is_correct = await ask_confirm(
|
||||
interaction,
|
||||
question=f'Looks like this is a {"triple" if num_outs == 3 else "double"} play! Is that correct?'
|
||||
)
|
||||
|
||||
if not is_correct:
|
||||
logger.warning(f'{interaction.user.name} marked this result incorrect')
|
||||
num_outs = 2 if num_outs == 3 else 3
|
||||
|
||||
if num_outs == 2:
|
||||
logger.info(f'Lead baserunner is out')
|
||||
this_play.outs = 2
|
||||
out_marked = False
|
||||
|
||||
if this_play.on_third is not None:
|
||||
this_play.on_third_final = None
|
||||
out_marked = True
|
||||
|
||||
elif this_play.on_second and not out_marked:
|
||||
this_play.on_second_final = None
|
||||
out_marked = True
|
||||
|
||||
elif this_play.on_first and not out_marked:
|
||||
this_play.on_first_final = None
|
||||
out_marked = True
|
||||
|
||||
else:
|
||||
logger.info(f'Two baserunners are out')
|
||||
this_play.outs = 3
|
||||
outs_marked = 1
|
||||
|
||||
if this_play.on_third is not None:
|
||||
this_play.on_third_final = None
|
||||
outs_marked += 1
|
||||
|
||||
elif this_play.on_second is not None:
|
||||
this_play.on_second_final = None
|
||||
outs_marked += 1
|
||||
|
||||
elif this_play.on_first is not None and outs_marked < 3:
|
||||
this_play.on_first_final = None
|
||||
outs_marked += 1
|
||||
|
||||
session.add(this_play)
|
||||
session.commit()
|
||||
|
||||
session.refresh(this_play)
|
||||
return this_play
|
||||
|
||||
|
||||
async def frame_checks(session: Session, interaction: discord.Interaction, this_play: Play):
|
||||
"""
|
||||
Commits this_play
|
||||
|
||||
24
dice.py
24
dice.py
@ -40,6 +40,10 @@ class FrameRoll(DiceRoll):
|
||||
is_walk: bool = False
|
||||
|
||||
|
||||
class DTwentyRoll(DiceRoll):
|
||||
pass
|
||||
|
||||
|
||||
def get_dice_embed(team: Team = None, embed_title: str = None):
|
||||
if team:
|
||||
embed = discord.Embed(
|
||||
@ -2837,6 +2841,26 @@ def ab_roll(this_team: Team, this_game: Game, allow_chaos: bool = True) -> AbRol
|
||||
return this_roll
|
||||
|
||||
|
||||
def d_twenty_roll(this_team: Team, this_game: Game) -> DTwentyRoll:
|
||||
logger.info(f'Rolling a d20 for {this_team.sname} in Game {this_game.id}')
|
||||
this_roll = DTwentyRoll(
|
||||
d_twenty=random.randint(1, 20)
|
||||
)
|
||||
|
||||
this_roll.roll_message = f'```md\n# {this_roll.d_twenty}\nDetails:[1d20 ({this_roll.d_twenty})]\n```'
|
||||
logger.info(f'D20 roll with message: {this_roll}')
|
||||
|
||||
embed = get_dice_embed(this_team)
|
||||
embed.add_field(
|
||||
name=f'D20 roll for the {this_team.sname}',
|
||||
value=this_roll.roll_message
|
||||
)
|
||||
|
||||
this_roll.embeds = [embed]
|
||||
|
||||
logger.info(f'Game {this_game.id} | Team {this_team.id} ({this_team.abbrev}): {this_roll.roll_message}')
|
||||
return this_roll
|
||||
|
||||
def jump_roll(this_team: Team, this_game: Game) -> JumpRoll:
|
||||
"""
|
||||
Check for a baserunner's jump before stealing
|
||||
|
||||
@ -563,6 +563,32 @@ class ManagerAi(ManagerAiBase, table=True):
|
||||
|
||||
return this_resp
|
||||
|
||||
def tag_from_third(self, session: Session, this_game: Game) -> TagResponse:
|
||||
this_resp = TagResponse()
|
||||
this_play = this_game.current_play_or_none(session)
|
||||
if this_play is None:
|
||||
raise GameException(f'No game found while checking tag_from_third')
|
||||
|
||||
ai_rd = this_play.ai_run_diff
|
||||
aggression_mod = abs(self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5)
|
||||
adjusted_running = self.running + aggression_mod
|
||||
|
||||
if adjusted_running >= 8:
|
||||
this_resp.min_safe = 7
|
||||
elif adjusted_running >= 5:
|
||||
this_resp.min_safe = 10
|
||||
else:
|
||||
this_resp.min_safe = 12
|
||||
|
||||
if ai_rd in [-1, 0]:
|
||||
this_resp.min_safe -= 2
|
||||
|
||||
if this_play.starting_outs == 1:
|
||||
this_resp.min_safe -= 2
|
||||
|
||||
return this_resp
|
||||
|
||||
|
||||
def throw_at_uncapped(self, session: Session, this_game: Game) -> ThrowResponse:
|
||||
this_resp = ThrowResponse()
|
||||
this_play = this_game.current_play_or_none(session)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user