Added random_gif() Moved back from exception-handler cog to local error handling Updated !keepers to be season agnostic Added new !sync param to update and clear local guild Added error checking to !player command
1258 lines
60 KiB
Python
1258 lines
60 KiB
Python
import math
|
|
|
|
import discord
|
|
from discord import app_commands
|
|
from discord.ext import commands
|
|
from peewee import IntegrityError
|
|
|
|
from typing import Optional, Literal
|
|
import logging
|
|
|
|
from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, LOGO, \
|
|
get_team_embed, Confirm, get_pos_abbrev, SBA_COLOR
|
|
from gameplay_helpers import *
|
|
from db_calls import get_one_team, get_one_player
|
|
from db_calls_gameplay import StratGame, StratPlay, StratLineup, get_one_game, pd_get_one_team, post_game, patch_game, \
|
|
get_game_team, post_lineups, pd_get_card_by_id, make_sub, get_player, player_link, get_team_lineups, \
|
|
get_current_play, post_play, get_one_lineup, advance_runners, patch_play, complete_play, get_batting_stats, \
|
|
get_pitching_stats, undo_play, get_latest_play, advance_one_runner, get_play_by_num
|
|
|
|
logger = logging.getLogger('discord_app')
|
|
|
|
class Gameplay(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
|
|
async def cog_command_error(self, ctx, error):
|
|
await ctx.send(f'{error}\n\nRun !help <command_name> to see the command requirements')
|
|
|
|
async def slash_error(self, ctx, error):
|
|
await ctx.send(f'{error}')
|
|
|
|
def get_scorebug(self, home_team, away_team, curr_play):
|
|
occupied = '●'
|
|
unoccupied = '○'
|
|
|
|
first_base = unoccupied if not curr_play.on_first else occupied
|
|
second_base = unoccupied if not curr_play.on_second else occupied
|
|
third_base = unoccupied if not curr_play.on_third else occupied
|
|
half = '▲' if curr_play.inning_half == 'Top' else '▼'
|
|
inning = f'{half} {curr_play.inning_num}'
|
|
outs = f'{curr_play.starting_outs} Out{"s" if curr_play.starting_outs != 1 else ""}'
|
|
|
|
game_string = f'```\n' \
|
|
f'{away_team["abbrev"]: ^4}{curr_play.away_score: ^3} {second_base}' \
|
|
f'{inning: >10}\n' \
|
|
f'{home_team["abbrev"]: ^4}{curr_play.home_score: ^3} {third_base} {first_base}' \
|
|
f'{outs: >8}\n```'
|
|
|
|
return game_string
|
|
|
|
async def get_game_state(self, game: StratGame) -> dict:
|
|
curr_play = get_current_play(game.id)
|
|
if curr_play is None:
|
|
latest_play = get_latest_play(game.id)
|
|
if not latest_play:
|
|
away_lineup = await get_team_lineups(game.id, game.away_team_id)
|
|
home_lineup = await get_team_lineups(game.id, game.home_team_id)
|
|
|
|
if len(away_lineup) == 0 or len(home_lineup) == 0:
|
|
game_state = {
|
|
'error': True,
|
|
'away_lineup': away_lineup,
|
|
'home_lineup': home_lineup
|
|
}
|
|
return game_state
|
|
else:
|
|
curr_play = post_play({
|
|
'game_id': game.id,
|
|
'play_num': 1,
|
|
'batter_id': get_one_lineup(game.id, game.away_team_id, batting_order=1).id,
|
|
'pitcher_id': get_one_lineup(game.id, game.home_team_id, position='P').id,
|
|
'on_base_code': 0,
|
|
'inning_half': 'Top',
|
|
'inning_num': 1,
|
|
'batting_order': 1,
|
|
'starting_outs': 0,
|
|
'away_score': 0,
|
|
'home_score': 0
|
|
})
|
|
else:
|
|
patch_play(latest_play.id, complete=False)
|
|
curr_play = latest_play
|
|
|
|
game_state = {'error': False, 'curr_play': curr_play}
|
|
|
|
away_team = await get_game_team(game, team_id=game.away_team_id)
|
|
home_team = await get_game_team(game, team_id=game.home_team_id)
|
|
game_state['away_team'] = away_team
|
|
game_state['home_team'] = home_team
|
|
|
|
scorebug = self.get_scorebug(home_team, away_team, game_state['curr_play'])
|
|
game_state['scorebug'] = scorebug
|
|
|
|
batter = await get_player(game, game_state['curr_play'].batter)
|
|
litmus = 0
|
|
try:
|
|
pitcher = await get_player(game, game_state['curr_play'].pitcher)
|
|
litmus = 1
|
|
catcher = await get_player(
|
|
game,
|
|
get_one_lineup(
|
|
game.id,
|
|
team_id=game.away_team_id if game_state['curr_play'].inning_half == 'Top' else game.home_team_id,
|
|
position='C'
|
|
)
|
|
)
|
|
except Exception as e:
|
|
logger.info(f'ERROR: {e} / TYPE: {type(e)}')
|
|
away_lineup = await get_team_lineups(game.id, game.away_team_id)
|
|
home_lineup = await get_team_lineups(game.id, game.home_team_id)
|
|
if litmus == 0:
|
|
error_message = f'Please sub in a pitcher to continue'
|
|
else:
|
|
error_message = f'Please sub in a catcher to continue'
|
|
|
|
game_state['error'] = True
|
|
game_state['error_message'] = error_message
|
|
game_state['away_lineup'] = away_lineup
|
|
game_state['home_lineup'] = home_lineup
|
|
return game_state
|
|
|
|
game_state['batter'] = batter
|
|
game_state['pitcher'] = pitcher
|
|
game_state['catcher'] = catcher
|
|
|
|
return game_state
|
|
|
|
async def get_game_state_embed(self, game: StratGame, full_length=True):
|
|
game_state = await self.get_game_state(game)
|
|
|
|
logger.info(f'game_state: {game_state}')
|
|
|
|
embed = get_team_embed(
|
|
f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}',
|
|
team=game_state['home_team'],
|
|
thumbnail=False
|
|
)
|
|
if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10:
|
|
embed.description = 'Mercy rule in effect'
|
|
|
|
if game.is_pd:
|
|
embed.set_footer(text=f'PD Season {PD_SEASON}', icon_url=LOGO)
|
|
|
|
embed.add_field(name='Game State', value=game_state['scorebug'], inline=False)
|
|
|
|
if game_state['error']:
|
|
# embed = discord.Embed(
|
|
# title='Current Lineups',
|
|
# color=int(SBA_COLOR, 16)
|
|
# )
|
|
embed.add_field(name='Away Team',
|
|
value=game_state['away_lineup'] if len(game_state['away_lineup']) else 'None, yet')
|
|
embed.add_field(name='Home Team',
|
|
value=game_state['home_lineup'] if len(game_state['home_lineup']) else 'None, yet')
|
|
if game_state['error_message']:
|
|
embed.set_footer(text=game_state['error_message'], icon_url=LOGO)
|
|
|
|
return embed
|
|
|
|
pitcher_string = f'{player_link(game, game_state["pitcher"])}'
|
|
batter_string = f'{player_link(game, game_state["batter"])}'
|
|
|
|
all_bat_stats = get_batting_stats(game.id, lineup_id=game_state['curr_play'].batter.id)
|
|
if len(all_bat_stats):
|
|
b_s = all_bat_stats[0]
|
|
batter_string += f'\n{b_s["pl_hit"]}-{b_s["pl_ab"]}'
|
|
for num, stat in [
|
|
(b_s['pl_double'], '2B'), (b_s['pl_triple'], '3B'), (b_s['pl_homerun'], 'HR'), (b_s['pl_rbi'], 'RBI'),
|
|
(b_s['pl_bb'], 'BB'), (b_s['pl_hbp'], 'HBP'), (b_s['pl_ibb'], 'IBB'), (b_s['pl_so'], 'K'),
|
|
(b_s['pl_gidp'], 'GIDP'), (b_s['pl_bpfo'], 'BPFO'), (b_s['pl_bplo'], 'BPLO')
|
|
]:
|
|
if num:
|
|
batter_string += f', {num if num > 1 else ""}{" " if num > 1 else ""}{stat}'
|
|
|
|
all_pit_stats = get_pitching_stats(game.id, lineup_id=game_state['curr_play'].pitcher.id)
|
|
if len(all_pit_stats):
|
|
p_s = all_pit_stats[0]
|
|
pitcher_string += f'\n{math.floor(p_s["pl_outs"]/3)}.{p_s["pl_outs"] % 3} IP'
|
|
for num, stat in [
|
|
(p_s['pl_runs'], 'R'), (p_s['pl_hit'], 'H'), (p_s['pl_homerun'], 'HR'), (p_s['pl_so'], 'K'),
|
|
(p_s['pl_bb'], 'BB'), (p_s['pl_hbp'], 'HBP'), (p_s['pl_wild_pitch'], 'WP'), (p_s['pl_balk'], 'BK'),
|
|
]:
|
|
if num:
|
|
pitcher_string += f', {num} {stat}'
|
|
if stat == 'R' and num != p_s['pl_eruns']:
|
|
pitcher_string += f', {p_s["pl_eruns"]} ER'
|
|
|
|
# embed.add_field(name='Matchup', value=f'Pitcher: \nvs\nBatter: ', inline=False)
|
|
embed.add_field(name='Pitcher', value=f'{pitcher_string}')
|
|
embed.add_field(name='Batter', value=f'{batter_string}')
|
|
embed.set_thumbnail(url=game_state["pitcher"]["image"])
|
|
embed.set_image(url=game_state["batter"]["image"])
|
|
|
|
baserunner_string = ''
|
|
if game_state['curr_play'].on_first:
|
|
runner = await get_player(game, game_state['curr_play'].on_first)
|
|
baserunner_string += f'On First: {player_link(game, runner)}\n'
|
|
if game_state['curr_play'].on_second:
|
|
runner = await get_player(game, game_state['curr_play'].on_second)
|
|
baserunner_string += f'On Second: {player_link(game, runner)}\n'
|
|
if game_state['curr_play'].on_third:
|
|
runner = await get_player(game, game_state['curr_play'].on_third)
|
|
baserunner_string += f'On Third: {player_link(game, runner)}\n'
|
|
embed.add_field(
|
|
name='Baserunners', value=baserunner_string if len(baserunner_string) > 0 else 'None', inline=False
|
|
)
|
|
|
|
if not full_length:
|
|
return embed
|
|
|
|
away_lineup = await get_team_lineups(game.id, game.away_team_id)
|
|
home_lineup = await get_team_lineups(game.id, game.home_team_id)
|
|
embed.add_field(name=f'{game_state["away_team"]["abbrev"]} Lineup', value=away_lineup)
|
|
embed.add_field(name=f'{game_state["home_team"]["abbrev"]} Lineup', value=home_lineup)
|
|
return embed
|
|
|
|
@commands.hybrid_command(name='newgame', help='Start a new baseball game')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_command(
|
|
self, ctx: commands.Context, away_team_abbrev: str, home_team_abbrev: str, week_num: int,
|
|
game_num: Optional[int] = None, is_pd: Optional[bool] = False):
|
|
conflict = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
if conflict:
|
|
await ctx.send(f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
f'before starting a new one.')
|
|
return
|
|
|
|
if is_pd:
|
|
away_team = pd_get_one_team(away_team_abbrev)
|
|
home_team = pd_get_one_team(home_team_abbrev)
|
|
if ctx.author.id not in [away_team['gmid'], home_team['gmid']]:
|
|
await ctx.send('You can only start a new game if you GM one of the teams.')
|
|
return
|
|
else:
|
|
away_team = await get_one_team(away_team_abbrev)
|
|
home_team = await get_one_team(home_team_abbrev)
|
|
if ctx.author.id not in [away_team['gmid'], away_team['gmid2'], home_team['gmid'], home_team['gmid2']]:
|
|
await ctx.send('You can only start a new game if you GM one of the teams.')
|
|
return
|
|
|
|
post_game({
|
|
'away_team_id': away_team['id'],
|
|
'home_team_id': home_team['id'],
|
|
'week_num': week_num,
|
|
'game_num': game_num,
|
|
'channel_id': ctx.channel.id,
|
|
'active': True,
|
|
'is_pd': is_pd
|
|
})
|
|
|
|
await ctx.send(random_conf_gif())
|
|
|
|
@commands.hybrid_command(name='endgame', help='End game in this channel')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def end_game_command(self, ctx: commands.Context):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
if not this_game:
|
|
await ctx.send(f'Ope, I don\'t see a game in this channel.')
|
|
return
|
|
|
|
patch_game(this_game.id, active=False)
|
|
|
|
# TODO: create result sheet and submit stats
|
|
if this_game.is_pd:
|
|
# Build the statlines
|
|
# Submit the scorecard
|
|
# Post a notification to PD for rewards
|
|
pass
|
|
else:
|
|
# Send stats to sheets
|
|
# Post sheets link
|
|
pass
|
|
|
|
await ctx.send(random_conf_gif())
|
|
|
|
@app_commands.command(
|
|
name='setlineup',
|
|
description='Set starting lineup for game in this channel; Player Name for SBa games / Card ID for PD games',
|
|
)
|
|
@app_commands.describe(
|
|
order_1_player='SBa: Player Name; PD: Card #',
|
|
order_1_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_2_player='SBa: Player Name; PD: Card #',
|
|
order_2_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_3_player='SBa: Player Name; PD: Card #',
|
|
order_3_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_4_player='SBa: Player Name; PD: Card #',
|
|
order_4_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_5_player='SBa: Player Name; PD: Card #',
|
|
order_5_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_6_player='SBa: Player Name; PD: Card #',
|
|
order_6_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_7_player='SBa: Player Name; PD: Card #',
|
|
order_7_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_8_player='SBa: Player Name; PD: Card #',
|
|
order_8_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_9_player='SBa: Player Name; PD: Card #',
|
|
order_9_pos='C for Catcher, 1B for first base, P for pitcher, etc.',
|
|
order_10_player='SBa: Player Name; PD: Card #; only used with a DH',
|
|
order_10_pos='P for pitcher; only used with a DH'
|
|
)
|
|
@app_commands.checks.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def set_lineup_command(
|
|
self, interaction: discord.Interaction, team_abbrev: str, order_1_player: str, order_1_pos: str,
|
|
order_2_player: str, order_2_pos: str, order_3_player: str, order_3_pos: str, order_4_player: str,
|
|
order_4_pos: str, order_5_player: str, order_5_pos: str, order_6_player: str, order_6_pos: str,
|
|
order_7_player: str, order_7_pos: str, order_8_player: str, order_8_pos: str, order_9_player: str,
|
|
order_9_pos: str, order_10_player: Optional[str] = None, order_10_pos: Optional[str] = 'P'):
|
|
this_game = get_one_game(channel_id=interaction.channel_id, active=True)
|
|
if not this_game:
|
|
await interaction.response.send_message(f'I dont\'t see an active game in this channel!')
|
|
return
|
|
|
|
owner_team = await get_game_team(this_game, interaction.user.id)
|
|
lineup_team = await get_game_team(this_game, team_abbrev=team_abbrev)
|
|
|
|
if not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
await interaction.response.send_message('Bruh. Only GMs of the active teams can set lineups.')
|
|
return
|
|
if not lineup_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
await interaction.response.send_message(f'I do not see {lineup_team["sname"]} in this game. Please check the team abbrev and '
|
|
f'try again')
|
|
return
|
|
|
|
existing_lineups = await get_team_lineups(this_game.id, lineup_team['id'])
|
|
if not existing_lineups or not len(existing_lineups):
|
|
await interaction.response.send_message(
|
|
f'It looks like the {lineup_team["sname"]} already have a lineup. Run `/substitution` to make changes.'
|
|
)
|
|
return
|
|
|
|
await interaction.response.defer()
|
|
|
|
all_lineups = []
|
|
all_pos = []
|
|
lineup_data = [
|
|
(order_1_player, order_1_pos), (order_2_player, order_2_pos), (order_3_player, order_3_pos),
|
|
(order_4_player, order_4_pos), (order_5_player, order_5_pos), (order_6_player, order_6_pos),
|
|
(order_7_player, order_7_pos), (order_8_player, order_8_pos), (order_9_player, order_9_pos),
|
|
(order_10_player, order_10_pos)
|
|
]
|
|
for index, pair in enumerate(lineup_data):
|
|
if not pair[0]:
|
|
break
|
|
|
|
if pair[1].upper() not in all_pos:
|
|
all_pos.append(pair[1].upper())
|
|
else:
|
|
raise SyntaxError(f'You have more than one {pair[1].upper()} in this lineup. Please update and set the '
|
|
f'lineup again.')
|
|
|
|
if this_game.is_pd:
|
|
this_card = pd_get_card_by_id(int(pair[0]))
|
|
if this_card['team']['id'] != lineup_team['id']:
|
|
raise SyntaxError(f'Easy there, champ. Looks like card ID {pair[0]} belongs to the '
|
|
f'{this_card["team"]["sname"]}. Try again with only cards you own.')
|
|
player_id = this_card['player']['id']
|
|
card_id = pair[0]
|
|
else:
|
|
this_player = await get_one_player(pair[0], season=SBA_SEASON)
|
|
if this_player['team']['id'] != lineup_team['id']:
|
|
raise SyntaxError(f'Easy there, champ. Looks like {pair[0]} is on '
|
|
f'{this_player["team"]["sname"]}. Try again with only your own players.')
|
|
player_id = this_player['id']
|
|
card_id = None
|
|
|
|
this_lineup = {
|
|
'game_id': this_game.id,
|
|
'team_id': lineup_team['id'],
|
|
'player_id': player_id,
|
|
'card_id': card_id,
|
|
'position': pair[1].upper(),
|
|
'batting_order': index + 1,
|
|
'after_play': 0
|
|
}
|
|
|
|
all_lineups.append(this_lineup)
|
|
|
|
logger.info(f'Setting lineup for {owner_team["sname"]} in {"PD" if this_game.is_pd else "SBa"} game')
|
|
post_lineups(all_lineups)
|
|
|
|
try:
|
|
await interaction.edit_original_response(content=None, embed=await self.get_game_state_embed(this_game))
|
|
except IntegrityError as e:
|
|
logger.info(f'Unable to pull game_state for game_id {this_game.id} until both lineups are in: {e}')
|
|
await interaction.response.send_message(f'Game state will be posted once both lineups are in')
|
|
return
|
|
|
|
@commands.hybrid_command(
|
|
name='substitution',
|
|
help='Make a lineup substitution; Player Name for SBa games / Card ID for PD games',
|
|
aliases=['sub']
|
|
)
|
|
@app_commands.describe(
|
|
new_player='For SBa game: enter the Player Name; for PD game: enter the Card ID (a number)')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def substitution_command(
|
|
self, ctx: commands.Context, team_abbrev: str, order_number: int, new_player: str, new_pos: str):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
if not this_game:
|
|
await ctx.send(f'I dont\'t see an active game in this channel!')
|
|
return
|
|
|
|
owner_team = await get_game_team(this_game, ctx.author.id)
|
|
lineup_team = await get_game_team(this_game, team_abbrev=team_abbrev)
|
|
|
|
if not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
await ctx.send('Bruh. Only GMs of the active teams can set lineups.')
|
|
return
|
|
|
|
if not lineup_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
await ctx.send(f'I do not see {lineup_team["sname"]} in this game. Please check the team abbrev and '
|
|
f'try again')
|
|
return
|
|
|
|
if this_game.is_pd:
|
|
this_card = pd_get_card_by_id(int(new_player))
|
|
if this_card["team"]["id"] != lineup_team['id']:
|
|
raise SyntaxError(f'Easy there, champ. Looks like card ID {new_player} belongs to the '
|
|
f'{this_card["team"]["sname"]}. Try again with only cards you own.')
|
|
player_id = this_card['player']['id']
|
|
card_id = new_player
|
|
else:
|
|
this_player = await get_one_player(new_player, season=SBA_SEASON)
|
|
if this_player['team']['id'] != lineup_team['id']:
|
|
raise SyntaxError(f'Easy there, champ. Looks like {new_player} is on '
|
|
f'{this_player["team"]["sname"]}. Try again with only your own players.')
|
|
player_id = this_player['id']
|
|
card_id = None
|
|
|
|
curr_play = get_current_play(this_game.id)
|
|
this_lineup = {
|
|
'game_id': this_game.id,
|
|
'team_id': lineup_team['id'],
|
|
'player_id': player_id,
|
|
'card_id': card_id,
|
|
'position': new_pos,
|
|
'batting_order': order_number,
|
|
'after_play': curr_play.play_num - 1
|
|
}
|
|
|
|
make_sub(this_lineup)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game))
|
|
|
|
@commands.hybrid_command(name='gamestate', help='Post the current game state', aliases=['gs'])
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def game_state_command(self, ctx: commands.Context, include_lineups: bool = True):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
if not this_game:
|
|
await ctx.send(f'I dont\'t see an active game in this channel!')
|
|
return
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=include_lineups))
|
|
|
|
async def checks_log_play(self, ctx: commands.Context) -> (Optional[StratGame], Optional[dict], Optional[StratPlay]):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
# if not this_game:
|
|
# return False, False, False
|
|
|
|
owner_team = await get_game_team(this_game, ctx.author.id)
|
|
if not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
await ctx.send('Bruh. Only GMs of the active teams can log plays.')
|
|
# return this_game, False, False
|
|
|
|
this_play = get_current_play(this_game.id)
|
|
if this_play.locked:
|
|
await ctx.send(f'Looks like this play is already being advanced. Please wait to log the next play.')
|
|
if not this_play.pitcher:
|
|
await ctx.send(f'Please sub in a pitcher before logging a new play.')
|
|
this_play = None
|
|
|
|
return this_game, owner_team, this_play
|
|
|
|
@commands.hybrid_group(name='log-onbase', help='Log a base hit in this channel\'s game')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def log_onbase(self, ctx: commands.Context):
|
|
if ctx.invoked_subcommand is None:
|
|
await ctx.send('No play details listed. Type `/log-onbase` to see available commands.')
|
|
|
|
@log_onbase.command(name='single-wellhit', help='Batter to first; runners advance two bases',
|
|
aliases=['siwh', 'si**', '1b**', '1bwh'])
|
|
async def log_single_wh_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
single_wellhit(this_play)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='single-onestar', help='Batter to first; runners advance one base', aliases=['si*', '1b*'])
|
|
async def log_single_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
single_onestar(this_play)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='ballpark-single', help='Batter to first; runners advance one base',
|
|
aliases=['bpsi', 'bp1b'])
|
|
async def log_ballpark_single_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1)
|
|
patch_play(this_play.id, pa=1, ab=1, hit=1, bp1b=1)
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='single-uncapped', help='Batter to first; runners may attempt to advance a second base',
|
|
aliases=['si', '1b'])
|
|
async def log_single_uncapped_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, hit=1)
|
|
advance_runners(this_play.id, 1)
|
|
this_play = get_current_play(this_game.id)
|
|
batter_to_base = 1
|
|
|
|
logger.info(f'this_play: {this_play}')
|
|
# Handle runner starting at second
|
|
if this_play.on_second:
|
|
this_runner = await get_player(this_game, this_play.on_second)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Was {this_runner["name"]} sent home?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view_two = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {this_runner["name"]} safe at the plate?', view=view_two)
|
|
await view_two.wait()
|
|
|
|
if view_two.value:
|
|
advance_one_runner(this_play.id, from_base=2, num_bases=2)
|
|
this_play = patch_play(this_play.id, rbi=this_play.rbi + 1)
|
|
else:
|
|
this_play = patch_play(this_play.id, on_second_final=99, outs=this_play.outs + 1)
|
|
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
|
|
logger.info(f'this_play: {this_play}')
|
|
# Handle runner starting at first
|
|
if this_play.on_first and (not this_play.on_second or this_play.on_second_final != 3):
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Was {this_runner["name"]} sent to third?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view_two = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {this_runner["name"]} safe at third?', view=view_two)
|
|
await view_two.wait()
|
|
|
|
if view_two.value:
|
|
advance_one_runner(this_play.id, from_base=1, num_bases=2)
|
|
this_play = get_current_play(this_game.id)
|
|
else:
|
|
this_play = patch_play(this_play.id, on_second_final=99, outs=1)
|
|
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
|
|
logger.info(f'this_play: {this_play}')
|
|
# Handle batter runner if either runner from first or runner from second advanced
|
|
if (this_play.on_first and this_play.on_first_final != 2) or \
|
|
(this_play.on_second and this_play.on_second_final != 3):
|
|
batter = await get_player(this_game, this_play.batter)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {batter["name"]} sent to second?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view_two = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {batter["name"]} safe at second?', view=view_two)
|
|
await view_two.wait()
|
|
|
|
if view_two.value:
|
|
batter_to_base = 2
|
|
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
|
|
logger.info(f'this_play: {this_play}')
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='double-twostar', help='Batter to second; runners advance two bases',
|
|
aliases=['do**', '2b**'])
|
|
async def log_double_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
double_twostar(this_play)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='double-uncapped', help='Batter to second; runners may attempt to advance a third base',
|
|
aliases=['do', '2b'])
|
|
async def log_double_uncapped_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, hit=1, double=1)
|
|
|
|
batter_to_base = 2
|
|
if this_play.on_first:
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Was {this_runner["name"]} sent home?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view_two = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {this_runner["name"]} safe at the plate?', view=view_two)
|
|
await view_two.wait()
|
|
|
|
if view_two.value:
|
|
advance_runners(this_play.id, num_bases=3)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=99, outs=1)
|
|
|
|
await question.delete()
|
|
batter = await get_player(this_game, this_play.batter)
|
|
view_three = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(
|
|
content=f'Did {batter["name"]} attempt the advance to third?', view=view_three
|
|
)
|
|
await view_three.wait()
|
|
|
|
if view_three.value:
|
|
await question.delete()
|
|
view_four = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(content=f'Was {batter["name"]} safe at third?', view=view_four)
|
|
await view_four.wait()
|
|
|
|
if view_four.value:
|
|
batter_to_base = 3
|
|
await question.delete()
|
|
else:
|
|
advance_runners(this_play.id, num_bases=2)
|
|
await question.delete()
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='double-threestar', help='Batter to second; runners advance three bases',
|
|
aliases=['dowh', 'do***'])
|
|
async def log_double_wh_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
double_threestar(this_play)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='triple', help='Batter to third; all runners score', aliases=['tr', '3b'])
|
|
async def log_triple_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
triple(this_play)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='homerun', help='Batter scores; all runners score', aliases=['hr', 'dong'])
|
|
async def log_homerun_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=4)
|
|
patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1)
|
|
complete_play(this_play.id)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='ballpark-homerun', help='Batter scores; all runners score', aliases=['bp-hr', 'bp-dong'])
|
|
async def log_homerun_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=3)
|
|
patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1, bphr=1)
|
|
complete_play(this_play.id)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='walk', help='Batter to first; runners advance if forced', aliases=['bb'])
|
|
async def log_walk_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
patch_play(this_play.id, pa=1, walk=1)
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='intentional-walk', help='Batter to first; runners advance if forced', aliases=['ibb'])
|
|
async def log_int_walk_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
patch_play(this_play.id, pa=1, ibb=1)
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_onbase.command(name='hit-by-pitch', help='Batter to first; runners advance if forced', aliases=['hbp'])
|
|
async def log_hit_by_pitch_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
patch_play(this_play.id, pa=1, hbp=1)
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@commands.hybrid_group(name='log-out', help='Log an out result in this channel\'s game')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def log_out(self, ctx: commands.Context):
|
|
if ctx.invoked_subcommand is None:
|
|
await ctx.send('No play details listed. Type `/log-out` to see available commands.')
|
|
|
|
@log_out.command(name='popout', help='Batter out; runners hold', aliases=['po'])
|
|
async def log_popout_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='strikeout', help='Batter out; runners hold', aliases=['so', 'k'])
|
|
async def log_strikeout_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1, so=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='lineout', help='Batter out; runners hold', aliases=['lo'])
|
|
async def log_lineout_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='sac-bunt', help='Batter out; runners advance one base', aliases=['sacb', 'bunt'])
|
|
async def log_sac_bunt_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1)
|
|
patch_play(this_play.id, pa=1, sac=1, outs=1)
|
|
complete_play(this_play.id)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='caught-stealing', help='One base runner is caught stealing', aliases=['cs'])
|
|
@app_commands.describe(
|
|
attempted_base='The base number the runner attempted to steal; 2 for 2nd, 3 for 3rd, 3 for home')
|
|
async def log_caught_stealing_command(self, ctx: commands.Context, attempted_base: int):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
catcher = get_one_lineup(
|
|
this_game.id, team_id=this_play.pitcher.team_id, position='C'
|
|
)
|
|
|
|
if attempted_base == 4 and this_play.on_third:
|
|
patch_play(
|
|
this_play.id, cs=1, on_third_final=99, runner_id=this_play.on_third.id,
|
|
catcher_id=catcher.id, outs=1
|
|
)
|
|
elif attempted_base == 3 and this_play.on_second:
|
|
if not this_play.on_third:
|
|
patch_play(
|
|
this_play.id, cs=1, on_second_final=99, runner_id=this_play.on_second.id,
|
|
catcher_id=catcher.id, outs=1
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_second)
|
|
await ctx.send(f'Ope. Looks like {this_runner["name"]} is blocked by the runner at third.')
|
|
return
|
|
elif attempted_base == 2 and this_play.on_first:
|
|
if not this_play.on_second:
|
|
patch_play(
|
|
this_play.id, cs=1, on_first_final=99, runner_id=this_play.on_first.id,
|
|
catcher_id=catcher.id, outs=1
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
await ctx.send(f'Ope. Looks like {this_runner["name"]} is blocked by the runner at second.')
|
|
return
|
|
else:
|
|
await ctx.send(f'Uh oh - I don\'t see a runner there to steal the bag.')
|
|
return
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='flyball-a', help='Batter out; all runners advance', aliases=['flya'])
|
|
async def log_flyballa_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
if this_play.starting_outs < 2:
|
|
advance_runners(this_play.id, 1)
|
|
if this_play.on_third:
|
|
patch_play(this_play.id, ab=0)
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='flyball-b', help='Batter out; runner on third scores', aliases=['flyb'])
|
|
async def log_flyballb_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
if this_play.starting_outs < 2 and this_play.on_third:
|
|
patch_play(this_play.id, ab=0, rbi=1)
|
|
advance_one_runner(this_play.id, from_base=3, num_bases=1)
|
|
|
|
if this_play.starting_outs < 2 and this_play.on_second:
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send('Did the runner on second advance?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
advance_one_runner(this_play.id, from_base=2, num_bases=1)
|
|
await question.edit(view=None)
|
|
else:
|
|
await question.delete()
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='flyball-bq', help='Batter out; runner on third may attempt to score', aliases=['flyb?'])
|
|
async def log_flyballbq_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
if this_play.starting_outs < 2 and this_play.on_third:
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send('Did the runner on third advance?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
advance_one_runner(this_play.id, from_base=3, num_bases=1)
|
|
patch_play(this_play.id, ab=0, rbi=1)
|
|
await question.edit(view=None)
|
|
else:
|
|
await question.delete()
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_out.command(name='flyball-c', help='Batter out; no runners advance', aliases=['flyc'])
|
|
async def log_flyballc_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@commands.hybrid_group(name='log-play', help='Log a result in this channel\'s game')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def log_play(self, ctx: commands.Context):
|
|
if ctx.invoked_subcommand is None:
|
|
await ctx.send('No play details listed. Type `/log` to see available commands.')
|
|
|
|
@log_play.command(name='undo-play', help='Remove the most recent play from the log', aliases=['undo', 'rollback'])
|
|
async def log_undo_play_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
undo_play(this_play.id)
|
|
undo_play(get_current_play(this_game.id).id)
|
|
complete_play(get_current_play(this_game.id).id, batter_to_base=get_latest_play(this_game.id).batter_final)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_play.command(name='stolen-base', help='One base runner steals a base', aliases=['sb'])
|
|
@app_commands.describe(stolen_base='The base number stolen by the runner; 2 for 2nd, 3 for 3rd, 4 for home')
|
|
async def log_stolen_base_command(self, ctx: commands.Context, stolen_base: int):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
catcher = get_one_lineup(
|
|
this_game.id, team_id=this_play.pitcher.team_id, position='C'
|
|
)
|
|
|
|
if stolen_base == 4 and this_play.on_third:
|
|
patch_play(
|
|
this_play.id, sb=1, on_third_final=4, runner_id=this_play.on_third.id, catcher_id=catcher.id
|
|
)
|
|
elif stolen_base == 3 and this_play.on_second:
|
|
if not this_play.on_third:
|
|
patch_play(
|
|
this_play.id, sb=1, on_second_final=3, runner_id=this_play.on_second.id, catcher_id=catcher.id
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_second)
|
|
await ctx.send(f'Ope. Looks like {this_runner["name"]} is blocked by the runner at third.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
elif stolen_base == 2 and this_play.on_first:
|
|
if not this_play.on_second:
|
|
patch_play(
|
|
this_play.id, sb=1, on_first_final=2, runner_id=this_play.on_first.id, catcher_id=catcher.id
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
await ctx.send(f'Ope. Looks like {this_runner["name"]} is blocked by the runner at second.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
else:
|
|
await ctx.send(f'Uh oh - I don\'t see a runner there to steal the bag.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_play.command(name='wild-pitch', help='All runners advance one base', aliases=['wp'])
|
|
async def log_wild_pitch_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, wp=1)
|
|
complete_play(this_play.id)
|
|
|
|
@log_play.command(name='passed-ball', help='All runners advance one base', aliases=['pb'])
|
|
async def log_passed_ball_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, pb=1)
|
|
complete_play(this_play.id)
|
|
|
|
@log_play.command(name='balk', help='All runners advance one base', aliases=['bk'])
|
|
async def log_balk_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, balk=1)
|
|
complete_play(this_play.id)
|
|
|
|
@log_play.command(name='pickoff', help='One baserunner is out on the basepaths', aliases=['pick'])
|
|
async def log_pickoff_command(self, ctx: commands.Context, from_base: int):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
if from_base == 3 and this_play.on_third:
|
|
patch_play(this_play.id, on_third_final=99, runner_id=this_play.on_third.id, outs=1)
|
|
elif from_base == 2 and this_play.on_second:
|
|
patch_play(this_play.id, on_second_final=99, runner_id=this_play.on_second.id, outs=1)
|
|
elif from_base == 1 and this_play.on_first:
|
|
patch_play(this_play.id, on_first_final=99, runner_id=this_play.on_first.id, outs=1)
|
|
else:
|
|
await ctx.send(f'Uh oh - I don\'t see a runner there to be picked off.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
complete_play(this_play.id)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@commands.hybrid_group(name='show-card', help='Display an active player\'s card')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def show_player(self, ctx: commands.Context):
|
|
if ctx.invoked_subcommand is None:
|
|
await ctx.send('No player details listed. Type `/show-player` to see available commands.')
|
|
|
|
@show_player.command(name='defense', help='Display a defender\'s player card', aliases=['pick'])
|
|
async def show_defense_command(
|
|
self, ctx: commands.Context, position: Literal[
|
|
'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', 'Center Field',
|
|
'Right Field']):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
defender = await get_player(
|
|
game=this_game,
|
|
lineup_member=get_one_lineup(
|
|
this_game.id, team_id=this_play.pitcher.team_id, position=get_pos_abbrev(position)
|
|
)
|
|
)
|
|
|
|
embed = get_team_embed(f'{defender["team"]["sname"]} {position}', defender['team'])
|
|
embed.description = f'{defender["name"]}'
|
|
embed.set_image(url=defender['image'])
|
|
if this_game.is_pd:
|
|
embed.set_footer(text=f'PD Season {PD_SEASON}', icon_url=LOGO)
|
|
|
|
await ctx.send(content=None, embed=embed)
|
|
|
|
@log_out.command(name='groundball-a', help='Potential double play ground ball', aliases=['gba'])
|
|
async def log_groundballa_command(self, ctx: commands.Context):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
batter_to_base = None
|
|
patch_play(this_play.id, locked=True)
|
|
if this_play.starting_outs == 2 or this_play.on_base_code == 0:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
else:
|
|
if this_play.on_base_code == 1:
|
|
runner = await get_player(this_game, this_play.on_first)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Is {runner["name"]} out at second on the double play?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2)
|
|
else:
|
|
await question.delete()
|
|
await ctx.send(f'Okay so it wasn\'t a gb A then? Go ahead and log a new play.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
elif this_play.on_base_code == 7:
|
|
runner = await get_player(this_game, this_play.on_third)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Is {runner["name"]} out on the home-to-first double play?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, on_third_final=False, pa=1, ab=1, outs=2, rbi=0)
|
|
else:
|
|
await question.delete()
|
|
runner = await get_player(this_game, this_play.on_second)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Is {runner["name"]} out at second on the double play?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value():
|
|
await question.delete()
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2, rbi=0)
|
|
else:
|
|
await question.delete()
|
|
await ctx.send(f'Okay so it wasn\'t a gb A then? Go ahead and log a new play.')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
else:
|
|
num_outs = 1
|
|
bases = ['third', 'second', 'first']
|
|
|
|
for count, x in enumerate([this_play.on_third, this_play.on_second, this_play.on_first]):
|
|
if x:
|
|
runner = await get_player(this_game, x)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(
|
|
f'Did {runner["name"]} advance from {bases[count]} on the play?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
num_bases = 0
|
|
if view.value:
|
|
await question.delete()
|
|
advance_one_runner(this_play.id, from_base=3 - count, num_bases=1)
|
|
else:
|
|
await question.delete()
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(f'Was {runner["name"]} doubled off?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
if count == 0:
|
|
patch_play(this_play.id, on_third_final=False)
|
|
elif count == 1:
|
|
patch_play(this_play.id, on_second_final=False)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=False)
|
|
num_outs += 1
|
|
else:
|
|
await question.delete()
|
|
if count == 0:
|
|
patch_play(this_play.id, on_third_final=3)
|
|
elif count == 1:
|
|
patch_play(this_play.id, on_second_final=2)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=1)
|
|
|
|
if this_play.on_third:
|
|
batter = await get_player(this_game, this_play.batter)
|
|
view = Confirm(responders=[ctx.author], timeout=60)
|
|
question = await ctx.send(
|
|
f'Is {batter["name"]} out at first?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
num_outs -= 1
|
|
batter_to_base = 1
|
|
|
|
patch_play(this_play.id, pa=1, ab=1, outs=num_outs)
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
@log_play.command(name='xcheck', help='Defender makes an x-check')
|
|
async def log_xcheck_command(self, ctx: commands.Context, position: Literal[
|
|
'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', 'Center Field',
|
|
'Right Field'], hit_allowed: Literal['out', 'single*', 'single**', 'double**', 'double***', 'triple'],
|
|
error_allowed: Literal['out', '1 base', '2 bases', '3 bases']):
|
|
this_game, owner_team, this_play = await self.checks_log_play(ctx)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
pos = get_pos_abbrev(position)
|
|
defender = get_one_lineup(
|
|
this_game.id, team_id=this_play.pitcher.team_id, position=pos
|
|
)
|
|
logger.info(f'defender: {defender}')
|
|
patch_play(this_play.id, defender_id=defender.id, error=1 if error_allowed != 'out' else 0, check_pos=pos)
|
|
|
|
# Not hit and no error
|
|
if hit_allowed == 'out' and error_allowed == 'out':
|
|
await ctx.send(f'Just logged the x-check! Please log the resulting play to continue (e.g. \'flyball-b\' or '
|
|
f'\'groundball-a\')')
|
|
return
|
|
|
|
# Hit and error
|
|
if hit_allowed != 'out' and error_allowed != 'out':
|
|
batter_to_base = 1
|
|
if hit_allowed == 'triple':
|
|
triple(this_play, comp_play=False)
|
|
elif 'double' in hit_allowed:
|
|
double_threestar(this_play, comp_play=False)
|
|
if error_allowed == '1 base':
|
|
batter_to_base = 3
|
|
elif error_allowed == '3 bases':
|
|
batter_to_base = 4
|
|
# 2 base error is the only one handled differently between doubles
|
|
elif hit_allowed == 'double***':
|
|
batter_to_base = 4
|
|
else:
|
|
batter_to_base = 3
|
|
# Both singles are handled the same
|
|
else:
|
|
single_wellhit(this_play, comp_play=False)
|
|
if error_allowed == '1 base':
|
|
batter_to_base = 2
|
|
else:
|
|
batter_to_base = 3
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
# Either hit or error
|
|
num_bases = None
|
|
if error_allowed == 'out':
|
|
if hit_allowed == 'single*':
|
|
single_onestar(this_play)
|
|
elif hit_allowed == 'single**':
|
|
single_wellhit(this_play)
|
|
elif hit_allowed == 'double**':
|
|
double_twostar(this_play)
|
|
elif hit_allowed == 'double***':
|
|
double_threestar(this_play)
|
|
elif hit_allowed == 'triple':
|
|
triple(this_play)
|
|
else:
|
|
if error_allowed == '1 base':
|
|
num_bases = 1
|
|
elif error_allowed == '2 bases':
|
|
num_bases = 2
|
|
elif error_allowed == '3 bases':
|
|
num_bases = 3
|
|
|
|
advance_runners(this_play.id, num_bases=num_bases, is_error=True)
|
|
complete_play(this_play.id, batter_to_base=num_bases)
|
|
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
|
|
# TODO: ground balls
|
|
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(Gameplay(bot))
|
|
|