3485 lines
165 KiB
Python
3485 lines
165 KiB
Python
import asyncio
|
|
import logging
|
|
import math
|
|
import copy
|
|
import os
|
|
|
|
import ai_manager
|
|
import discord
|
|
import gauntlets
|
|
from discord import app_commands
|
|
from discord.app_commands import Choice
|
|
from discord.ext import commands, tasks
|
|
from peewee import IntegrityError
|
|
|
|
from typing import Optional, Literal
|
|
|
|
from dice import sa_fielding_roll
|
|
from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, IMAGES, \
|
|
get_team_embed, Confirm, get_pos_abbrev, SBA_COLOR, get_roster_lineups, Question, give_packs, send_to_channel, \
|
|
get_channel, get_or_create_role, team_role, get_cal_user, get_card_embeds, ButtonOptions, get_ratings_guide, \
|
|
get_team_by_owner, get_roster_sheet
|
|
from gameplay_helpers import *
|
|
from db_calls import db_get, db_patch, db_post, db_delete, get_team_by_abbrev
|
|
from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, get_sba_team, get_sba_player, \
|
|
post_game, patch_game, get_game_team, post_lineups, 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, count_team_games, get_final_scorebug, \
|
|
get_fielding_stats, get_pitching_decisions, get_or_create_bullpen, get_last_inning_end_play, patch_lineup, \
|
|
get_last_game_ids, get_plays, get_manager, get_one_game, load_ai, ai_batting
|
|
|
|
|
|
class Gameplay(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.batter_ratings = None
|
|
self.pitcher_ratings = None
|
|
self.live_scoreboard.start()
|
|
|
|
@tasks.loop(minutes=5)
|
|
async def live_scoreboard(self):
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
if not guild:
|
|
logging.error(f'Cannot access guild; pausing for 15 seconds')
|
|
await asyncio.sleep(15)
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
if not guild:
|
|
logging.error(f'Still cannot access guild; trying again in 10 minutes')
|
|
return
|
|
|
|
all_games = get_last_game_ids(6)
|
|
|
|
games_active = False
|
|
for game_id in all_games:
|
|
g_query = get_one_game(game_id)
|
|
if g_query.active:
|
|
games_active = True
|
|
|
|
if games_active:
|
|
embed = get_team_embed(f'Live Scoreboard')
|
|
for game_id in all_games:
|
|
try:
|
|
gs = await self.get_game_state(get_one_game(game_id=game_id))
|
|
logging.debug(f'curr_play: {gs["curr_play"]}')
|
|
g_message = gs['scorebug']
|
|
|
|
if not gs['curr_play'].game.active:
|
|
g_dec = get_pitching_decisions(gs['curr_play'].game)
|
|
winner = await get_player(gs["curr_play"].game, g_dec["w_lineup"])
|
|
loser = await get_player(gs["curr_play"].game, g_dec["l_lineup"])
|
|
if g_dec['s_lineup']:
|
|
saver = await get_player(gs['curr_play'].game, g_dec['s_lineup'])
|
|
s_string = f'Save: {saver["name"]}\n' \
|
|
f'Location: {guild.get_channel(gs["channel_id"]).mention}\n' \
|
|
f'\n-------------------------'
|
|
else:
|
|
s_string = f'Location: {guild.get_channel(gs["channel_id"]).mention}\n' \
|
|
f'-------------------------'
|
|
|
|
g_message += f'Win: {winner["name"]}\n' \
|
|
f'Loss: {loser["name"]}\n' \
|
|
f'{s_string}'
|
|
else:
|
|
games_active = True
|
|
g_message += f'Pitcher: {gs["pitcher"]["name"]}\n' \
|
|
f'Batter: {gs["batter"]["name"]}\n' \
|
|
f'Location: {guild.get_channel(gs["channel_id"]).mention}\n' \
|
|
f'-------------------------'
|
|
|
|
embed.add_field(
|
|
name=f'{gs["away_team"]["sname"]} @ {gs["home_team"]["sname"]}',
|
|
value=g_message,
|
|
inline=False
|
|
)
|
|
|
|
except Exception as e:
|
|
logging.error(
|
|
f'Skipping Game {game_id} in scoreboard: {e}'
|
|
)
|
|
|
|
current = db_get('current')
|
|
|
|
try:
|
|
s_channel = self.bot.get_channel(int(os.environ.get('SCOREBOARD_CHANNEL')))
|
|
message_id = current['live_scoreboard']
|
|
if message_id == 0:
|
|
s_message = await send_to_channel(
|
|
self.bot,
|
|
'live-scoreboard',
|
|
content=None,
|
|
embed=embed
|
|
)
|
|
db_patch('current', object_id=current['id'], params=[('live_scoreboard', s_message.id)])
|
|
|
|
else:
|
|
s_message = await s_channel.fetch_message(message_id)
|
|
await s_message.edit(content=None, embed=embed)
|
|
|
|
except Exception as e:
|
|
logging.error(f'Unable to post scoreboard: {e}')
|
|
|
|
@tasks.loop(hours=36)
|
|
async def update_ratings_guides(self):
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
if not guild:
|
|
logging.error(f'Cannot access guild; pausing ratings guide for 20 seconds')
|
|
await asyncio.sleep(20)
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
if not guild:
|
|
logging.error(f'Still cannot access guild; trying again in 1 minutes')
|
|
await asyncio.sleep(60)
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
if not guild:
|
|
logging.error(f'Still cannot access guild; dueces')
|
|
return
|
|
|
|
data = get_ratings_guide(get_sheets(self.bot))
|
|
if data['valid']:
|
|
self.batter_ratings = data['batter_ratings']
|
|
self.pitcher_ratings = data['pitcher_ratings']
|
|
else:
|
|
logging.error(f'gameplay - pulled bad ratings guide data')
|
|
|
|
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 '▼'
|
|
if curr_play.game.active:
|
|
inning = f'{half} {curr_play.inning_num}'
|
|
outs = f'{curr_play.starting_outs} Out{"s" if curr_play.starting_outs != 1 else ""}'
|
|
else:
|
|
inning = f'F/{curr_play.inning_num if curr_play.inning_half == "Bot" else curr_play.inning_num - 1}'
|
|
outs = ''
|
|
|
|
game_string = f'```\n' \
|
|
f'{away_team["abbrev"].replace("Gauntlet-", ""): ^4}{curr_play.away_score: ^3} {second_base}' \
|
|
f'{inning: >10}\n' \
|
|
f'{home_team["abbrev"].replace("Gauntlet-", ""): ^4}{curr_play.home_score: ^3} {third_base} ' \
|
|
f'{first_base}{outs: >8}\n```'
|
|
|
|
return game_string
|
|
|
|
async def get_game_state(self, game: StratGame) -> dict:
|
|
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)
|
|
|
|
curr_play = get_current_play(game.id)
|
|
if curr_play is None:
|
|
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 not away_lineup or not home_lineup:
|
|
game_state = {
|
|
'error': True,
|
|
'away_lineup': away_lineup,
|
|
'home_lineup': home_lineup,
|
|
'away_team': away_team,
|
|
'home_team': home_team
|
|
}
|
|
logging.error(f'One ore more lineups not submitted in Game {game.id}\n\ngame_state: {game_state}')
|
|
return game_state
|
|
else:
|
|
logging.info(f'looking for home ({game.home_team_id}) pitcher in Game {game.id}')
|
|
pitcher = get_one_lineup(game.id, team_id=game.home_team_id, position='P')
|
|
logging.info(f'pitcher: {pitcher}')
|
|
curr_play = post_play({
|
|
'game_id': game.id,
|
|
'play_num': 1,
|
|
'batter_id': get_one_lineup(game.id, team_id=game.away_team_id, batting_order=1).id,
|
|
'pitcher_id': pitcher.id if pitcher else None,
|
|
'on_base_code': 0,
|
|
'inning_half': 'Top',
|
|
'inning_num': 1,
|
|
'batting_order': 1,
|
|
'starting_outs': 0,
|
|
'away_score': 0,
|
|
'home_score': 0
|
|
})
|
|
|
|
game_state = {'error': False, 'curr_play': curr_play, 'away_team': away_team, 'home_team': home_team}
|
|
|
|
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:
|
|
if not game_state['curr_play'].pitcher:
|
|
p_search = get_one_lineup(
|
|
game.id,
|
|
team_id=game.away_team_id if game_state['curr_play'].inning_half == 'Bot' else game.home_team_id,
|
|
position='P'
|
|
)
|
|
if p_search:
|
|
patch_play(game_state['curr_play'].id, pitcher_id=p_search.id)
|
|
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 == 'Bot' else game.home_team_id,
|
|
position='C'
|
|
)
|
|
)
|
|
except Exception as e:
|
|
logging.error(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
|
|
game_state['channel_id'] = game.channel_id
|
|
|
|
return game_state
|
|
|
|
async def get_game_state_embed(self, game: StratGame, full_length=True, for_liveboard=False):
|
|
game_state = await self.get_game_state(game)
|
|
|
|
logging.debug(f'game_state: {game_state}')
|
|
|
|
embed = discord.Embed(
|
|
title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}',
|
|
color=int(SBA_COLOR, 16)
|
|
)
|
|
|
|
if game.is_pd:
|
|
footer_text = f'PD Season {PD_SEASON}'
|
|
if game.short_game:
|
|
footer_text += f' - Reminder: all pitchers have POW(1) in 3-inning games'
|
|
embed.set_footer(text=footer_text, icon_url=IMAGES['logo'])
|
|
else:
|
|
embed.set_footer(text=f'SBa Season {SBA_SEASON}', icon_url=IMAGES['logo'])
|
|
|
|
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 game_state['away_lineup'] else 'None, yet')
|
|
embed.add_field(name='Home Team',
|
|
value=game_state['home_lineup'] if game_state['home_lineup'] else 'None, yet')
|
|
if 'error_message' in game_state:
|
|
embed.set_footer(text=game_state['error_message'], icon_url=IMAGES['logo'])
|
|
|
|
return embed
|
|
|
|
embed.add_field(name='Game State', value=game_state['scorebug'], inline=False)
|
|
|
|
if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10:
|
|
embed.description = '***Mercy rule in effect***'
|
|
|
|
pitcher_string = f'{player_link(game, game_state["pitcher"])}'
|
|
batter_string = f'{game_state["curr_play"].batter.batting_order}. {player_link(game, game_state["batter"])} - ' \
|
|
f'{game_state["curr_play"].batter.position}'
|
|
|
|
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'
|
|
if game.short_game and p_s["pl_outs"] >= 3:
|
|
pitcher_string += f'\n***F A T I G U E D***'
|
|
|
|
# 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"])
|
|
if game_state['batter']['image2']:
|
|
embed.set_image(url=game_state["batter"]["image2"])
|
|
else:
|
|
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 an AI team is playing
|
|
if True in [game_state['pitcher']['team']['is_ai'], game_state['batter']['team']['is_ai']]:
|
|
ai_note = ''
|
|
gm_name = ''
|
|
logging.debug(f'Checking AI stuff')
|
|
|
|
# AI Team is pitching
|
|
if game_state['pitcher']['team']['is_ai']:
|
|
this_ai = get_manager(game)
|
|
logging.debug(f'Pitching team is an AI')
|
|
gm_name = f'{game_state["pitcher"]["team"]["gmname"]}'
|
|
used_pitchers = await get_team_lineups(
|
|
game_id=game_state['curr_play'].game.id,
|
|
team_id=game_state["pitcher"]["team"]['id'],
|
|
inc_inactive=True,
|
|
pitchers_only=True,
|
|
as_string=False
|
|
)
|
|
|
|
last_inning_ender = get_last_inning_end_play(
|
|
game.id,
|
|
game_state['curr_play'].inning_half,
|
|
game_state['curr_play'].inning_num - 1
|
|
)
|
|
logging.debug(f'last_inning_ender: {last_inning_ender}')
|
|
|
|
if last_inning_ender and last_inning_ender.pitcher != game_state['curr_play'].pitcher:
|
|
logging.debug(f'{game_state["pitcher"]["team"]["sname"]} not making a change.')
|
|
|
|
ai_note += f'- have {game_state["pitcher"]["p_name"]} finish the inning\n'
|
|
|
|
elif game_state['curr_play'].is_new_inning and game.short_game and game_state['curr_play'].inning_num != 1:
|
|
logging.debug(f'{game_state["pitcher"]["team"]["sname"]} going the to pen.')
|
|
|
|
if len(used_pitchers) < 8:
|
|
make_sub(ai_manager.get_relief_pitcher(
|
|
game_state['curr_play'], game_state['pitcher']['team'], used_pitchers, game.game_type
|
|
))
|
|
new_pitcher = await get_player(game, get_pitcher(game, game_state['curr_play']))
|
|
embed.set_thumbnail(url=new_pitcher['image'])
|
|
embed.add_field(
|
|
name=f'SUBSTITUTION',
|
|
value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in '
|
|
f'{new_pitcher["p_name"]} to pitch.'
|
|
)
|
|
else:
|
|
ai_note += f'- continue with auto-fatigued {game_state["pitcher"]["p_name"]}\n'
|
|
|
|
else:
|
|
if len(used_pitchers) < 8:
|
|
ai_note += f'- go to the pen if the pitcher fatigues (`/log ai-pitcher-sub`)\n'
|
|
else:
|
|
ai_note += f' - continue with {game_state["pitcher"]["p_name"]}\n'
|
|
|
|
logging.debug(f'past the first conditional in AI stuff')
|
|
|
|
if game_state['curr_play'].on_base_code > 0 and game_state['curr_play'].starting_outs == 2:
|
|
ai_note += f'- hold the runners'
|
|
elif game_state['curr_play'].on_base_code == 1:
|
|
ai_note += f'- only hold baserunners with an ***** auto-jump\n'
|
|
elif game_state['curr_play'].on_base_code == 2:
|
|
ai_note += f'- only hold baserunners with a safe range of 14+\n'
|
|
|
|
if game_state['curr_play'].on_third and game_state['curr_play'].starting_outs < 2:
|
|
if game_state['curr_play'].on_first:
|
|
ai_note += f'- play the corners in\n'
|
|
|
|
elif abs(game_state['curr_play'].away_score - game_state['curr_play'].home_score) <= 3:
|
|
ai_note += f'- play the whole infield in\n'
|
|
|
|
else:
|
|
ai_note += f'- play the corners in\n'
|
|
|
|
# AI Team is batting
|
|
elif game_state['batter']['team']['is_ai']:
|
|
this_ai = get_manager(game)
|
|
logging.debug(f'Batting team is an AI')
|
|
gm_name = f'{game_state["batter"]["team"]["gmname"]}'
|
|
if game_state['curr_play'].on_first and not game_state['curr_play'].on_second:
|
|
ai_note += f'- {this_ai.check_jump(2, game_state["curr_play"])}\n'
|
|
|
|
elif game_state['curr_play'].on_second and not game_state['curr_play'].on_third:
|
|
ai_note += f'- {this_ai.check_jump(3, game_state["curr_play"])}\n'
|
|
|
|
if ai_note:
|
|
embed.add_field(
|
|
name=f'{gm_name} will...',
|
|
value=ai_note,
|
|
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
|
|
|
|
async def groundballs(
|
|
self, interaction, this_game, this_play: StratPlay, groundball_type: str, comp_play: bool = True):
|
|
batter_to_base = None
|
|
bases = ['third', 'second', 'first']
|
|
|
|
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 groundball_type == 'a':
|
|
if this_play.on_base_code == 1:
|
|
patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2)
|
|
|
|
elif this_play.on_base_code == 4:
|
|
if this_play.starting_outs == 1:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=2)
|
|
else:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is the double play at second and first?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(
|
|
this_play.id,
|
|
pa=1,
|
|
ab=1,
|
|
outs=2,
|
|
on_second_final=3,
|
|
on_first_final=False,
|
|
)
|
|
|
|
else:
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is the double play at third and second?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(
|
|
this_play.id,
|
|
pa=1,
|
|
ab=1,
|
|
outs=2,
|
|
on_second_final=False,
|
|
on_first_final=False
|
|
)
|
|
batter_to_base = 1
|
|
|
|
else:
|
|
await question.edit(
|
|
content=f'Hmm...not sure what else this could be. If you expected a different '
|
|
f'result, let Cal know.',
|
|
view=None
|
|
)
|
|
return
|
|
|
|
elif this_play.on_base_code == 7:
|
|
if this_play.starting_outs == 1:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=2)
|
|
else:
|
|
runner = await get_player(this_game, this_play.on_third)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.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()
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=2, rbi=0)
|
|
|
|
else:
|
|
num_outs = 1
|
|
|
|
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=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from {bases[count]} on the play?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
num_bases = 0
|
|
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
|
|
)
|
|
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=4)
|
|
elif count == 1:
|
|
patch_play(this_play.id, on_second_final=3)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=2)
|
|
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=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.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)
|
|
if num_outs + this_play.starting_outs == 3:
|
|
advance_runners(this_play.id, 0)
|
|
|
|
elif groundball_type == 'b':
|
|
if this_play.on_base_code == 3 or this_play.on_base_code == 6 or this_play.on_base_code == 2:
|
|
if this_play.on_base_code == 2:
|
|
runner = await get_player(this_game, this_play.on_second)
|
|
from_base = 'second'
|
|
else:
|
|
runner = await get_player(this_game, this_play.on_third)
|
|
from_base = 'third'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from {from_base} on the play?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
advance_runners(this_play.id, 1)
|
|
|
|
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
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
if from_base == 'third':
|
|
patch_play(this_play.id, on_third_final=False)
|
|
|
|
# from second
|
|
else:
|
|
patch_play(this_play.id, on_second_final=False)
|
|
else:
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 0)
|
|
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
|
|
elif this_play.on_base_code == 1 or this_play.on_base_code == 4:
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, on_first_final=False, pa=1, ab=1, outs=1)
|
|
batter_to_base = 1
|
|
|
|
else:
|
|
num_outs = 0
|
|
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=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from {bases[count]} on the play?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
num_bases = 0
|
|
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
|
|
)
|
|
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()
|
|
advance_one_runner(this_play.id, from_base=3 - count, num_bases=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 num_outs == 0:
|
|
batter = await get_player(this_game, this_play.batter)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {batter["name"]} out at first?', view=view
|
|
)
|
|
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
num_outs += 1
|
|
else:
|
|
await question.delete()
|
|
await interaction.edit_original_response(
|
|
content=f'Okay so it wasn\'t a gb B then? Go ahead and log a new play.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
else:
|
|
batter_to_base = 1
|
|
|
|
patch_play(this_play.id, pa=1, ab=1, outs=num_outs)
|
|
|
|
elif groundball_type == 'c':
|
|
if this_play.on_base_code == 7:
|
|
runner = await get_player(this_game, this_play.on_third)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {runner["name"]} forced out at home?', 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=1, rbi=0)
|
|
batter_to_base = 1
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
|
|
elif this_play.on_third:
|
|
num_outs = 0
|
|
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=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from {bases[count]} on the play?', 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
|
|
)
|
|
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=4)
|
|
elif count == 1:
|
|
patch_play(this_play.id, on_second_final=3)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=2)
|
|
|
|
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 not num_outs:
|
|
num_outs += 1
|
|
|
|
logging.debug(f'should be patching the gb C now...')
|
|
patch_play(this_play.id, pa=1, ab=1, outs=num_outs)
|
|
|
|
else:
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
|
|
if comp_play:
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
async def flyballs(self, interaction, this_game, this_play, flyball_type, comp_play: bool = True):
|
|
num_outs = 1
|
|
|
|
if flyball_type == 'a':
|
|
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)
|
|
|
|
elif flyball_type == 'b' or flyball_type == 'ballpark':
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1, bpfo=1 if flyball_type == 'ballpark' else 0)
|
|
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:
|
|
ai_hint = ''
|
|
if this_game.ai_team and ai_batting(this_game, this_play):
|
|
ai_hint = f'*The runner will {get_manager(this_game).tag_from_second(this_play.starting_outs + 1)}*'
|
|
runner = await get_player(this_game, this_play.on_second)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from second on the play?\n\n{ai_hint}', 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':
|
|
advance_one_runner(this_play.id, from_base=2, num_bases=1)
|
|
elif view.value == 'Out at 3rd':
|
|
num_outs += 1
|
|
patch_play(this_play.id, on_second_final=False, outs=num_outs)
|
|
else:
|
|
await question.delete()
|
|
else:
|
|
await question.delete()
|
|
|
|
elif flyball_type == 'b?':
|
|
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:
|
|
ai_hint = ''
|
|
if ai_batting(this_game, this_play):
|
|
ai_hint = f'*The runner will {get_manager(this_game).tag_from_third(this_play.starting_outs + 1)}*'
|
|
runner = await get_player(this_game, this_play.on_third)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was {runner["name"]} sent from third on the play?\n\n{ai_hint}', 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
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(this_play.id, on_third_final=False)
|
|
num_outs += 1
|
|
patch_play(this_play.id, outs=num_outs)
|
|
else:
|
|
await question.delete()
|
|
advance_one_runner(this_play.id, from_base=3, num_bases=1)
|
|
else:
|
|
await question.delete()
|
|
|
|
elif flyball_type == 'c':
|
|
patch_play(this_play.id, locked=True, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, num_bases=0)
|
|
|
|
if comp_play:
|
|
complete_play(this_play.id)
|
|
|
|
# @commands.command(name='tl')
|
|
# @commands.is_owner()
|
|
# async def test_lineup_command(self, ctx, team_abbrev: str):
|
|
# t_query = db_get('teams', params=[('abbrev', team_abbrev)])
|
|
# if t_query['count'] > 0:
|
|
# team = t_query['teams'][0]
|
|
# await ctx.send(f'Pulling a lineup for the {team["lname"]}...')
|
|
# lineups = ai_manager.build_lineup(team, 69420, 'l', 'minor-league')
|
|
# l_output = ''
|
|
# for line in lineups:
|
|
# l_output += f'{line["batting_order"]} - {line["player_name"]} - {line["position"]}\n'
|
|
# await ctx.send(f'Lineups:\n\n{l_output}')
|
|
# else:
|
|
# await ctx.send(f'No team found with abbrev {team_abbrev}')
|
|
#
|
|
# @commands.command(name='tr')
|
|
# @commands.is_owner()
|
|
# async def test_reliever_command(self, ctx, game_id: int):
|
|
# this_game = get_one_game(game_id=game_id)
|
|
# ai_id = this_game.away_team_id if this_game.ai_team == 'away' else this_game.home_team_id
|
|
# ai_team = db_get('teams', object_id=ai_id)
|
|
# used_pitchers = await get_team_lineups(
|
|
# game_id=game_id, team_id=ai_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
|
|
# )
|
|
# reliever = ai_manager.get_relief_pitcher(get_current_play(game_id), ai_team, used_pitchers)
|
|
# await ctx.send(f'Reliever selected:\n\n{reliever}')
|
|
|
|
group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game')
|
|
|
|
# @group_new_game.command(name='sba', description='Start a new SBa league game')
|
|
# @commands.has_any_role(SBA_PLAYERS_ROLE_NAME)
|
|
# async def new_game_command(
|
|
# self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str, week_num: int,
|
|
# game_num: int):
|
|
# await interaction.response.defer()
|
|
#
|
|
# conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
# if conflict:
|
|
# await interaction.edit_original_response(
|
|
# content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
# f'before starting a new one.')
|
|
# return
|
|
#
|
|
# away_team = get_sba_team(away_team_abbrev)
|
|
# home_team = get_sba_team(home_team_abbrev)
|
|
# for x in [away_team, home_team]:
|
|
# conflict = count_team_games(x['id'])
|
|
# if conflict['count']:
|
|
# await interaction.edit_original_response(
|
|
# content=f'Ope. The {x["sname"]} are already playing over in '
|
|
# f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}'
|
|
# )
|
|
# return
|
|
#
|
|
# if interaction.user.id not in [away_team['gmid'], away_team['gmid2'], home_team['gmid'], home_team['gmid2']]:
|
|
# await interaction.edit_original_response(
|
|
# content='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'],
|
|
# 'season': SBA_SEASON,
|
|
# 'week_num': week_num,
|
|
# 'game_num': game_num,
|
|
# 'channel_id': interaction.channel.id,
|
|
# 'active': True,
|
|
# 'is_pd': False,
|
|
# })
|
|
# logging.info(f'game is posted!')
|
|
#
|
|
# await interaction.edit_original_response(
|
|
# content=f'The game is set! Go ahead and set lineups with `/setlineup`'
|
|
# )
|
|
|
|
@group_new_game.command(name='mlb-campaign', description='Start a new MLB Campaign game against an AI')
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_campaign_command(
|
|
self, interaction: discord.Interaction, league: Literal['Minor League', 'Major League', 'Hall of Fame'],
|
|
away_team_abbrev: str, home_team_abbrev: str, num_innings: Literal[9, 3]):
|
|
await interaction.response.defer()
|
|
|
|
conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if conflict:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
f'before starting a new one.')
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != 'Public Fields':
|
|
await interaction.response.send_message(
|
|
f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
|
f'pops up?'
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logging.error(f'Could not check channel category: {e}')
|
|
|
|
away_team = get_team_by_abbrev(away_team_abbrev)
|
|
home_team = get_team_by_abbrev(home_team_abbrev)
|
|
|
|
if not away_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
if not home_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
|
|
# if True in [away_team['is_ai'], home_team['is_ai']] and is_ranked:
|
|
# await interaction.edit_original_response(
|
|
# content=f'Sorry, ranked games can only be played against human teams. Run `/new-game` again with '
|
|
# f'`is_ranked` set to False to play against the '
|
|
# f'{away_team["sname"] if away_team["is_ai"] else home_team["sname"]}.'
|
|
# )
|
|
# return
|
|
|
|
for x in [away_team, home_team]:
|
|
if not x['is_ai']:
|
|
conflict = count_team_games(x['id'])
|
|
if conflict['count']:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. The {x["sname"]} are already playing over in '
|
|
f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}'
|
|
)
|
|
return
|
|
|
|
current = db_get('current')
|
|
week_num = current['week']
|
|
# logging.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: {is_ranked}')
|
|
logging.debug(f'away: {away_team} / home: {home_team} / week: {week_num}')
|
|
|
|
if not away_team['is_ai'] and not home_team['is_ai']:
|
|
logging.error(f'MLB Campaign game between {away_team["abbrev"]} and {home_team["abbrev"]} has no AI')
|
|
await interaction.edit_original_response(
|
|
content=f'I don\'t see an AI team in this MLB Campaign game. Run `/new-game mlb-campaign` again with '
|
|
f'an AI for a campaign game or `/new-game <ranked / unlimited>` for a human game.'
|
|
)
|
|
return
|
|
|
|
ai_team = away_team if away_team['is_ai'] else home_team
|
|
|
|
if interaction.user.id not in [away_team['gmid'], home_team['gmid']]:
|
|
await interaction.edit_original_response(
|
|
content='You can only start a new game if you GM one of the teams.'
|
|
)
|
|
return
|
|
|
|
if 'Minor' in league:
|
|
league_name = 'minor-league'
|
|
elif 'Major' in league:
|
|
can_play = False
|
|
for x in interaction.user.roles:
|
|
if x.name == 'PD - Major League':
|
|
can_play = True
|
|
|
|
if not can_play:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. Looks like you haven\'t received the **PD - Major League** role, yet!\n\n'
|
|
f'To play **Major League** games, you need to defeat all 30 MLB teams in the Minor League '
|
|
f'campaign. You can see your progress with `/record`.\n\n'
|
|
f'If you have completed the Minor League campaign, go ping Cal to get your new role!')
|
|
return
|
|
league_name = 'major-league'
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content='Hall of Fame games are coming next season! For now, you can play an Unlimited Minor League '
|
|
'game or against other humans!'
|
|
)
|
|
return
|
|
league_name = 'hall-of-fame'
|
|
|
|
this_game = post_game({
|
|
'away_team_id': away_team['id'],
|
|
'home_team_id': home_team['id'],
|
|
'week_num': week_num,
|
|
'channel_id': interaction.channel.id,
|
|
'active': True,
|
|
'is_pd': True,
|
|
'ranked': False,
|
|
'season': current['season'],
|
|
'short_game': True if num_innings == 3 else False,
|
|
'game_type': league_name
|
|
})
|
|
logging.info(
|
|
f'Game {this_game.id} between {away_team_abbrev.upper()} and {home_team_abbrev.upper()} is posted!'
|
|
)
|
|
away_role = await team_role(interaction, away_team)
|
|
home_role = await team_role(interaction, home_team)
|
|
|
|
# Get AI Lineup
|
|
try:
|
|
await interaction.edit_original_response(
|
|
content=f'I am getting a lineup card from the {ai_team["sname"]}...'
|
|
)
|
|
|
|
logging.info(f'new-game - calling lineup for {ai_team["abbrev"]}')
|
|
all_lineups = ai_manager.build_lineup(ai_team, this_game.id, league_name)
|
|
logging.info(f'new-game - got lineup for {ai_team["abbrev"]}')
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logging.error(f'could not start an AI game with {ai_team["sname"]}: {e}')
|
|
await interaction.edit_original_response(
|
|
content=f'Looks like the {ai_team["sname"]} lineup card didn\'t come through clearly. I\'ll sort '
|
|
f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end '
|
|
f'this game - why don\'t you play against somebody else for now?'
|
|
)
|
|
return
|
|
|
|
# Get AI Starting Pitcher
|
|
try:
|
|
await interaction.edit_original_response(
|
|
content=f'Now to decide on a Starting Pitcher...'
|
|
)
|
|
if ai_team['id'] == this_game.away_team_id:
|
|
patch_game(this_game.id, away_roster_num=69, ai_team='away')
|
|
else:
|
|
patch_game(this_game.id, home_roster_num=69, ai_team='home')
|
|
|
|
# starter = starting_pitcher(ai_team, self.bot, True if home_team['is_ai'] else False)
|
|
starter = ai_manager.get_starting_pitcher(
|
|
ai_team,
|
|
this_game.id,
|
|
True if home_team['is_ai'] else False,
|
|
league_name
|
|
)
|
|
all_lineups.append(starter)
|
|
|
|
this_card = db_get(f'cards', object_id=starter['card_id'])
|
|
await interaction.channel.send(
|
|
content=f'The {ai_team["sname"]} are starting **{this_card["player"]["description"]}**:\n\n'
|
|
f'{this_card["player"]["image"]}'
|
|
)
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logging.error(f'could not start an AI game with {ai_team["sname"]}: {e}')
|
|
await interaction.edit_original_response(
|
|
content=f'Looks like the {ai_team["sname"]} rotation didn\'t come through clearly. I\'ll sort '
|
|
f'this out with {ai_team["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end '
|
|
f'this game - why don\'t you play against somebody else for now?'
|
|
)
|
|
return
|
|
|
|
logging.debug(f'Setting lineup for {ai_team["sname"]} in PD game')
|
|
post_lineups(all_lineups)
|
|
|
|
await interaction.channel.send(
|
|
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
|
|
f'Go ahead and set lineups with the `/readlineup` command!',
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
|
|
@group_new_game.command(name='ranked', description='Start a new Ranked game against another human')
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_ranked_command(
|
|
self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str,
|
|
num_innings: Literal[9, 3]):
|
|
await interaction.response.defer()
|
|
|
|
conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if conflict:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
f'before starting a new one.')
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != 'Public Fields':
|
|
await interaction.response.send_message(
|
|
f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
|
f'pops up?'
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logging.error(f'Could not check channel category: {e}')
|
|
|
|
away_team = get_team_by_abbrev(away_team_abbrev)
|
|
home_team = get_team_by_abbrev(home_team_abbrev)
|
|
|
|
if not away_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
if not home_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
|
|
if away_team['is_ai'] or home_team['is_ai']:
|
|
logging.error(f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI')
|
|
await interaction.edit_original_response(
|
|
content=f'Only human vs human games can be ranked - run `/new-game` again and double-check the '
|
|
f'game type you want! If you have questions, feel free to post up in #paper-dynasty-chat'
|
|
)
|
|
return
|
|
|
|
for x in [away_team, home_team]:
|
|
if not x['is_ai']:
|
|
conflict = count_team_games(x['id'])
|
|
if conflict['count']:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. The {x["sname"]} are already playing over in '
|
|
f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}'
|
|
)
|
|
return
|
|
|
|
current = db_get('current')
|
|
week_num = current['week']
|
|
logging.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: True')
|
|
|
|
if interaction.user.id not in [away_team['gmid'], home_team['gmid']]:
|
|
await interaction.edit_original_response(
|
|
content='You can only start a new game if you GM one of the teams.'
|
|
)
|
|
return
|
|
|
|
this_game = post_game({
|
|
'away_team_id': away_team['id'],
|
|
'home_team_id': home_team['id'],
|
|
'week_num': week_num,
|
|
'channel_id': interaction.channel.id,
|
|
'active': True,
|
|
'is_pd': True,
|
|
'ranked': True,
|
|
'season': current['season'],
|
|
'short_game': True if num_innings == 3 else False,
|
|
'game_type': 'ranked'
|
|
})
|
|
logging.info(
|
|
f'Game {this_game.id} between {away_team_abbrev.upper()} and {home_team_abbrev.upper()} is posted!'
|
|
)
|
|
away_role = await team_role(interaction, away_team)
|
|
home_role = await team_role(interaction, home_team)
|
|
|
|
await interaction.channel.send(
|
|
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
|
|
f'Go ahead and set lineups with the `/readlineup` command!',
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
|
|
@group_new_game.command(name='unlimited', description='Start a new Unlimited game against another human')
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_unlimited_command(
|
|
self, interaction: discord.Interaction, away_team_abbrev: str, home_team_abbrev: str,
|
|
num_innings: Literal[9, 3]):
|
|
await interaction.response.defer()
|
|
|
|
conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if conflict:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
f'before starting a new one.')
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != 'Public Fields':
|
|
await interaction.response.send_message(
|
|
f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
|
f'pops up?'
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logging.error(f'Could not check channel category: {e}')
|
|
|
|
away_team = get_team_by_abbrev(away_team_abbrev)
|
|
home_team = get_team_by_abbrev(home_team_abbrev)
|
|
|
|
if not away_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{away_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
if not home_team:
|
|
await interaction.edit_original_response(
|
|
content=f'Sorry, I don\'t know who **{home_team_abbrev.upper()}** is.'
|
|
)
|
|
return
|
|
|
|
if away_team['is_ai'] or home_team['is_ai']:
|
|
logging.error(f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI')
|
|
await interaction.edit_original_response(
|
|
content=f'This command is for human v human games - run `/new-game` again and double-check the '
|
|
f'game type you want! If you have questions, feel free to post up in #paper-dynasty-chat'
|
|
)
|
|
return
|
|
|
|
for x in [away_team, home_team]:
|
|
if not x['is_ai']:
|
|
conflict = count_team_games(x['id'])
|
|
if conflict['count']:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. The {x["sname"]} are already playing over in '
|
|
f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}'
|
|
)
|
|
return
|
|
|
|
current = db_get('current')
|
|
week_num = current['week']
|
|
logging.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: True')
|
|
|
|
if interaction.user.id not in [away_team['gmid'], home_team['gmid']]:
|
|
await interaction.edit_original_response(
|
|
content='You can only start a new game if you GM one of the teams.'
|
|
)
|
|
return
|
|
|
|
this_game = post_game({
|
|
'away_team_id': away_team['id'],
|
|
'home_team_id': home_team['id'],
|
|
'week_num': week_num,
|
|
'channel_id': interaction.channel.id,
|
|
'active': True,
|
|
'is_pd': True,
|
|
'ranked': False,
|
|
'season': current['season'],
|
|
'short_game': True if num_innings == 3 else False,
|
|
'game_type': 'unlimited'
|
|
})
|
|
logging.info(
|
|
f'Game {this_game.id} between {away_team_abbrev.upper()} and {home_team_abbrev.upper()} is posted!'
|
|
)
|
|
away_role = await team_role(interaction, away_team)
|
|
home_role = await team_role(interaction, home_team)
|
|
|
|
await interaction.channel.send(
|
|
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
|
|
f'Go ahead and set lineups with the `/readlineup` command!',
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
|
|
@group_new_game.command(name='gauntlet', description='Start a new Gauntlet game against an AI')
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_gauntlet_command(self, interaction: discord.Interaction, event_name: Literal['Paper Sluggers']):
|
|
await interaction.response.defer()
|
|
|
|
conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if conflict:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. There is already a game going on in this channel. Please wait for it to complete '
|
|
f'before starting a new one.')
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != 'Public Fields':
|
|
await interaction.response.send_message(
|
|
f'Why don\'t you head down to one of the Public Fields that way other humans can help if anything '
|
|
f'pops up?'
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logging.error(f'Could not check channel category: {e}')
|
|
|
|
current = db_get('current')
|
|
week_num = current['week']
|
|
|
|
e_query = db_get('events', params=[("name", event_name), ("active", True)])
|
|
if e_query['count'] == 0:
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like the {event_name} has ended! Cal should really remove it from this list.'
|
|
)
|
|
return
|
|
this_event = e_query['events'][0]
|
|
|
|
main_team = get_team_by_owner(interaction.user.id)
|
|
team = get_team_by_abbrev(f'Gauntlet-{main_team["abbrev"]}')
|
|
if not main_team:
|
|
await interaction.edit_original_response(
|
|
content=f'I don\'t see a team for you, yet. You can sign up with the `/newteam` command!'
|
|
)
|
|
return
|
|
if not team:
|
|
await interaction.edit_original_response(
|
|
content=f'I don\'t see an active run for you. You can get started with the `/gauntlets start` command!'
|
|
)
|
|
return
|
|
|
|
conflict = count_team_games(team['id'])
|
|
if conflict['count']:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. The {team["sname"]} are already playing over in '
|
|
f'{interaction.guild.get_channel(conflict["games"][0]["channel_id"]).mention}'
|
|
)
|
|
return
|
|
|
|
# Get Gauntlet run
|
|
r_query = db_get(
|
|
'gauntletruns',
|
|
params=[('team_id', team['id']), ('gauntlet_id', this_event['id']), ('is_active', True)]
|
|
)
|
|
|
|
if r_query['count'] == 0:
|
|
await interaction.channel.send(
|
|
f'I don\'t see an active run for you. If you would like to start a new one, run '
|
|
f'`/new-game gauntlet {this_event["name"]}` and we can get you started in no time!'
|
|
)
|
|
return
|
|
|
|
this_run = r_query['runs'][0]
|
|
|
|
# If not new or after draft, create new AI game
|
|
is_home = gauntlets.is_home_team(team, this_event, this_run)
|
|
opponent = gauntlets.get_opponent(team, this_event, this_run)
|
|
if opponent is None:
|
|
await interaction.edit_original_response(
|
|
content=f'Yike. I\'m not sure who your next opponent is. {get_cal_user(interaction)} help plz!'
|
|
)
|
|
return
|
|
|
|
game_code = gauntlets.get_game_code(team, this_event, this_run)
|
|
this_game = post_game({
|
|
'away_team_id': opponent['id'] if is_home else team['id'],
|
|
'home_team_id': team['id'] if is_home else opponent['id'],
|
|
'week_num': week_num,
|
|
'channel_id': interaction.channel.id,
|
|
'active': True,
|
|
'is_pd': True,
|
|
'ranked': False,
|
|
'season': current['season'],
|
|
'short_game': False,
|
|
'game_type': game_code
|
|
})
|
|
logging.info(
|
|
f'Game {this_game.id} between {team["abbrev"]} and {opponent["abbrev"]} is posted!'
|
|
)
|
|
t_role = await team_role(interaction, main_team)
|
|
|
|
# Get AI Lineup
|
|
try:
|
|
await interaction.edit_original_response(
|
|
content=f'I am getting a lineup card from the {opponent["sname"]}...'
|
|
)
|
|
|
|
logging.info(f'new-game - calling lineup for {opponent["abbrev"]}')
|
|
all_lineups = gauntlets.build_lineup(opponent, this_game, this_event)
|
|
logging.info(f'new-game-gauntlet - got lineup for {opponent["abbrev"]}')
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logging.error(f'could not start a gauntlet game with {opponent["sname"]}: {e}')
|
|
await interaction.edit_original_response(
|
|
content=f'Looks like the {opponent["sname"]} lineup card didn\'t come through clearly. I\'ll sort '
|
|
f'this out with {opponent["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end '
|
|
f'this game - why don\'t you play against somebody else for now?'
|
|
)
|
|
return
|
|
|
|
# Get AI Starting Pitcher
|
|
try:
|
|
await interaction.edit_original_response(
|
|
content=f'Now to decide on a Starting Pitcher...'
|
|
)
|
|
if opponent['id'] == this_game.away_team_id:
|
|
patch_game(this_game.id, away_roster_num=69, ai_team='away')
|
|
else:
|
|
patch_game(this_game.id, home_roster_num=69, ai_team='home')
|
|
|
|
starter = gauntlets.get_starting_pitcher(opponent, this_game, this_event, this_run)
|
|
all_lineups.append(starter)
|
|
|
|
this_card = db_get(f'cards', object_id=starter['card_id'])
|
|
await interaction.channel.send(
|
|
content=f'The {opponent["sname"]} are starting **{this_card["player"]["description"]}**:\n\n'
|
|
f'{this_card["player"]["image"]}'
|
|
)
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logging.error(f'could not start an AI game with {opponent["sname"]}: {e}')
|
|
await interaction.edit_original_response(
|
|
content=f'Looks like the {opponent["sname"]} rotation didn\'t come through clearly. I\'ll sort '
|
|
f'this out with {opponent["gmname"]} and {get_cal_user(interaction).mention}. I\'ll end '
|
|
f'this game - why don\'t you play against somebody else for now?'
|
|
)
|
|
return
|
|
|
|
logging.debug(f'Setting lineup for {opponent["sname"]} in PD Gauntlet game {game_code}')
|
|
post_lineups(all_lineups)
|
|
|
|
await interaction.channel.send(
|
|
content=f'Game {gauntlets.games_played(this_run) + 1} of the run is set!\n\n'
|
|
f'Go ahead and set lineups with the `/readlineup` command!',
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
|
|
@commands.command(name='force-endgame', help='Mod: Force a game to end without stats')
|
|
@commands.is_owner()
|
|
async def force_end_game_command(self, ctx: commands.Context):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
|
|
try:
|
|
await ctx.send(content=None, embed=await self.get_game_state_embed(this_game))
|
|
except Exception as e:
|
|
logging.error(f'could not post game state embed: {e}')
|
|
question = await ctx.send(
|
|
f'Something is very borked here and I can\'t post the embed. Imma nuke this game now...'
|
|
)
|
|
patch_game(this_game.id, active=False)
|
|
await question.edit(content='Done and dusted.', view=None)
|
|
return
|
|
|
|
view = Confirm(responders=[ctx.author], timeout=60, label_type='yes')
|
|
question = await ctx.send(f'Should I nuke this game?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
patch_game(this_game.id, active=False)
|
|
await question.edit(content='It\'s gone.', view=None)
|
|
else:
|
|
await question.edit(content='It stays.', view=None)
|
|
|
|
@commands.command(name='check-decisions', help='Mod: Calculate pitching decisions of current game')
|
|
@commands.is_owner()
|
|
async def check_decisions_command(self, ctx: commands.Context):
|
|
this_game = get_one_game(channel_id=ctx.channel.id, active=True)
|
|
get_pitching_decisions(this_game)
|
|
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
|
|
logging.info(f'Ending Game {this_game.id}')
|
|
|
|
response = await ctx.send(f'Let\'s see what we\'ve got here...')
|
|
|
|
owner_team = await get_game_team(this_game, ctx.author.id)
|
|
gauntlet_team = None
|
|
if 'gauntlet' in this_game.game_type:
|
|
gauntlet_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}')
|
|
|
|
if not {owner_team['id'], gauntlet_team['id']}.intersection(
|
|
[this_game.away_team_id, this_game.home_team_id]):
|
|
await ctx.send('Bruh. Only GMs of the active teams can end games.')
|
|
return
|
|
elif not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id] and \
|
|
ctx.author.id != self.bot.owner_id:
|
|
await ctx.send('Bruh. Only GMs of the active teams can end games.')
|
|
return
|
|
|
|
await response.edit(content=None, embed=await self.get_game_state_embed(this_game))
|
|
view = Confirm(responders=[ctx.author], timeout=60, label_type='yes')
|
|
question = await ctx.send(f'Should I end this game?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.edit(content='I\'ll tally the scorecard now...', view=None)
|
|
else:
|
|
await question.edit(content='It stays.', view=None)
|
|
return
|
|
|
|
away_team = db_get('teams', object_id=this_game.away_team_id)
|
|
home_team = db_get('teams', object_id=this_game.home_team_id)
|
|
|
|
away_stats = {
|
|
# 'p_lines': get_pitching_stats(this_game.id, team_id=away_team['id']),
|
|
'p_lines': [],
|
|
'b_lines': get_batting_stats(this_game.id, team_id=away_team['id']),
|
|
'f_lines': get_fielding_stats(this_game.id, team_id=away_team['id'])
|
|
}
|
|
home_stats = {
|
|
# 'p_lines': get_pitching_stats(this_game.id, team_id=home_team['id']),
|
|
'p_lines': [],
|
|
'b_lines': get_batting_stats(this_game.id, team_id=home_team['id']),
|
|
'f_lines': get_fielding_stats(this_game.id, team_id=home_team['id']),
|
|
# 'score': away_stats['p_lines'][0]['tm_runs']
|
|
}
|
|
|
|
logging.debug(f'away_stats: {away_stats}\n\nhome_stats: {home_stats}')
|
|
|
|
away_pitchers = await get_team_lineups(
|
|
this_game.id, team_id=away_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
|
|
)
|
|
for line in away_pitchers:
|
|
try:
|
|
# logging.info(f'line: {line}')
|
|
this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
|
|
# logging.info(f'away / this_stats: {this_stats}')
|
|
away_stats['p_lines'].extend(this_stats)
|
|
if 'score' not in home_stats:
|
|
# logging.info(f'score not in home_stats')
|
|
home_stats['score'] = this_stats[0]['pl_runs']
|
|
else:
|
|
# logging.info(f'score is in home_stats')
|
|
home_stats['score'] += this_stats[0]['pl_runs']
|
|
if 'hits' not in home_stats:
|
|
# logging.info(f'hits not in home_stats')
|
|
home_stats['hits'] = this_stats[0]['pl_hit']
|
|
else:
|
|
# logging.info(f'hits is in home_stats')
|
|
home_stats['hits'] += this_stats[0]['pl_hit']
|
|
except Exception as e:
|
|
bad_player = await get_player(this_game, line)
|
|
logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: '
|
|
f'{type(e)}: {e}')
|
|
await ctx.send(f'I was not able to process stats for {bad_player["name"]} - {get_cal_user(ctx).mention}'
|
|
f' help!')
|
|
|
|
home_pitchers = await get_team_lineups(
|
|
this_game.id, team_id=home_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
|
|
)
|
|
for line in home_pitchers:
|
|
try:
|
|
# logging.info(f'line: {line}')
|
|
this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
|
|
# logging.info(f'home / this_stats: {this_stats}')
|
|
home_stats['p_lines'].extend(this_stats)
|
|
if 'score' not in away_stats:
|
|
# logging.info(f'score not in away_stats')
|
|
away_stats['score'] = this_stats[0]['pl_runs']
|
|
else:
|
|
# logging.info(f'score is in away_stats')
|
|
away_stats['score'] += this_stats[0]['pl_runs']
|
|
if 'hits' not in away_stats:
|
|
# logging.info(f'hits not in away_stats')
|
|
away_stats['hits'] = this_stats[0]['pl_hit']
|
|
else:
|
|
# logging.info(f'hits is in away_stats')
|
|
away_stats['hits'] += this_stats[0]['pl_hit']
|
|
except Exception as e:
|
|
bad_player = await get_player(this_game, line)
|
|
logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: '
|
|
f'{type(e)}: {e}')
|
|
await ctx.send(f'I was not able to process stats for {bad_player["name"]} - {get_cal_user(ctx).mention}'
|
|
f' help!')
|
|
|
|
logging.debug(f'finished tallying pitcher stats')
|
|
|
|
# away_stats['score'] = home_stats['p_lines'][0]['tm_runs']
|
|
try:
|
|
decisions = get_pitching_decisions(this_game)
|
|
except AttributeError as e:
|
|
logging.error(f'Could not pull decisions for Game {this_game.id}: {e}')
|
|
await ctx.send(f'I was not able to calculate the Winning and Losing Pitcher for this game. Is the game '
|
|
f'ending early? {get_cal_user(ctx).mention} can probably help.')
|
|
return
|
|
logging.debug(f'decisions: {decisions}')
|
|
|
|
wr_query = db_get(
|
|
'gamerewards', params=[('name', f'{"Short" if this_game.short_game else "Full"} Game Win')])
|
|
lr_query = db_get(
|
|
'gamerewards', params=[('name', f'{"Short" if this_game.short_game else "Full"} Game Loss')])
|
|
if not wr_query['count'] or not lr_query['count']:
|
|
raise KeyError(f'Game Rewards were not found. Leaving this game active.')
|
|
win_reward = wr_query['gamerewards'][0]
|
|
loss_reward = lr_query['gamerewards'][0]
|
|
winning_team = away_team if away_stats['score'] > home_stats['score'] else home_team
|
|
losing_team = away_team if away_stats['score'] < home_stats['score'] else home_team
|
|
|
|
# Check for Gauntlet game so rewards go to main team
|
|
if gauntlet_team is not None:
|
|
if winning_team['gmid'] == gauntlet_team['gmid']:
|
|
winning_team = owner_team
|
|
else:
|
|
losing_team = owner_team
|
|
|
|
logging.debug(f'away_stats (in /endgame function)\n\n{away_stats}')
|
|
logging.debug(f'home_stats (in /endgame function)\n\n{home_stats}')
|
|
logging.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}')
|
|
|
|
if this_game.is_pd:
|
|
logging.debug(f'Time to build statlines and submit the scorecard for this PD game!')
|
|
# Post result
|
|
success = db_post(
|
|
'results',
|
|
payload={
|
|
'away_team_id': this_game.away_team_id,
|
|
'home_team_id': this_game.home_team_id,
|
|
'away_score': away_stats['score'],
|
|
'home_score': home_stats['score'],
|
|
'away_team_ranking': away_team['ranking'],
|
|
'home_team_ranking': home_team['ranking'],
|
|
'scorecard': f'Bot Game {this_game.id}',
|
|
'week': this_game.week_num,
|
|
'season': this_game.season,
|
|
'ranked': this_game.ranked,
|
|
'short_game': this_game.short_game,
|
|
'game_type': this_game.game_type
|
|
}
|
|
)
|
|
# Submit the stats
|
|
batter_stats = []
|
|
pitcher_stats = []
|
|
doubles = ''
|
|
triples = ''
|
|
homers = ''
|
|
s_bases = ''
|
|
caught_s = ''
|
|
|
|
for line in [*away_stats['b_lines'], *home_stats['b_lines']]:
|
|
if line['pl_double']:
|
|
if len(doubles):
|
|
doubles += ', '
|
|
doubles += f'{db_get("cards", object_id=line["card_id"])["player"]["p_name"]}' \
|
|
f'{" " if line["pl_double"] > 1 else ""}' \
|
|
f'{line["pl_double"] if line["pl_double"] > 1 else ""}'
|
|
if line['pl_triple']:
|
|
if len(triples):
|
|
triples += ', '
|
|
triples += f'{db_get("cards", object_id=line["card_id"])["player"]["p_name"]}' \
|
|
f'{" " if line["pl_triple"] > 1 else ""}' \
|
|
f'{line["pl_triple"] if line["pl_triple"] > 1 else ""}'
|
|
if line['pl_homerun']:
|
|
if len(homers):
|
|
homers += ', '
|
|
homers += f'{db_get("cards", object_id=line["card_id"])["player"]["p_name"]}' \
|
|
f'{" " if line["pl_homerun"] > 1 else ""}' \
|
|
f'{line["pl_homerun"] if line["pl_homerun"] > 1 else ""}'
|
|
if line['pl_sb']:
|
|
if len(s_bases):
|
|
s_bases += ', '
|
|
s_bases += f'{db_get("cards", object_id=line["card_id"])["player"]["p_name"]}' \
|
|
f'{" " if line["pl_sb"] > 1 else ""}' \
|
|
f'{line["pl_sb"] if line["pl_sb"] > 1 else ""}'
|
|
batter_stats.append(
|
|
{
|
|
'card_id': line['card_id'],
|
|
'team_id': line['team_id'],
|
|
'roster_num':
|
|
this_game.away_roster_num if this_game.away_team_id == line['team_id']
|
|
else this_game.home_roster_num,
|
|
'vs_team_id':
|
|
home_team['id'] if this_game.away_team_id == line['team_id']
|
|
else away_team['id'],
|
|
'pos': line['pos'],
|
|
'pa': line['pl_pa'],
|
|
'ab': line['pl_ab'],
|
|
'run': line['pl_run'],
|
|
'rbi': line['pl_rbi'],
|
|
'hit': line['pl_hit'],
|
|
'double': line['pl_double'],
|
|
'triple': line['pl_triple'],
|
|
'hr': line['pl_homerun'],
|
|
'bb': line['pl_bb'],
|
|
'so': line['pl_so'],
|
|
'hbp': line['pl_hbp'],
|
|
'sac': line['pl_sac'],
|
|
'ibb': line['pl_ibb'],
|
|
'gidp': line['pl_gidp'],
|
|
'sb': line['pl_sb'],
|
|
'cs': line['pl_cs'],
|
|
'bphr': line['pl_bphr'],
|
|
'bpfo': line['pl_bpfo'],
|
|
'bp1b': line['pl_bp1b'],
|
|
'bplo': line['pl_bplo'],
|
|
'week': this_game.week_num,
|
|
'season': this_game.season,
|
|
'game_id': this_game.id,
|
|
}
|
|
)
|
|
|
|
for line in [*away_stats['f_lines'], *home_stats['f_lines']]:
|
|
if line['pl_csc']:
|
|
if len(caught_s):
|
|
caught_s += ', '
|
|
caught_s += f'{db_get("cards", object_id=line["card_id"])["player"]["p_name"]}' \
|
|
f'{" " if line["pl_csc"] > 1 else ""}' \
|
|
f'{line["pl_csc"] if line["pl_csc"] > 1 else ""}'
|
|
batter_stats.append(
|
|
{
|
|
'card_id': line['card_id'],
|
|
'team_id': line['team_id'],
|
|
'roster_num':
|
|
this_game.away_roster_num if this_game.away_team_id == line['team_id']
|
|
else this_game.home_roster_num,
|
|
'vs_team_id':
|
|
home_team['id'] if this_game.away_team_id == line['team_id']
|
|
else away_team['id'],
|
|
'pos': line['pos'],
|
|
'xch': line['pl_xch'],
|
|
'xhit': line['pl_xhit'],
|
|
'error': line['pl_error'],
|
|
'pb': line['pl_pb'],
|
|
'sbc': line['pl_sbc'],
|
|
'csc': line['pl_csc'],
|
|
'week': this_game.week_num,
|
|
'season': this_game.season,
|
|
'game_id': this_game.id
|
|
}
|
|
)
|
|
|
|
for line in [*away_stats['p_lines'], *home_stats['p_lines']]:
|
|
pitcher_stats.append(
|
|
{
|
|
'card_id': line['card_id'],
|
|
'team_id': line['team_id'],
|
|
'roster_num':
|
|
this_game.away_roster_num if this_game.away_team_id == line['team_id']
|
|
else this_game.home_roster_num,
|
|
'vs_team_id':
|
|
home_team['id'] if this_game.away_team_id == line['team_id']
|
|
else away_team['id'],
|
|
'ip': (math.floor(line['pl_outs'] / 3) * 1.0) + ((line['pl_outs'] % 3) / 3.0),
|
|
'hit': line['pl_hit'],
|
|
'run': line['pl_runs'],
|
|
'erun': line['pl_eruns'],
|
|
'so': line['pl_so'],
|
|
'bb': line['pl_bb'],
|
|
'hbp': line['pl_hbp'],
|
|
'wp': line['pl_wild_pitch'],
|
|
'balk': line['pl_balk'],
|
|
'hr': line['pl_homerun'],
|
|
'ir': 0,
|
|
'irs': 0,
|
|
'gs': 1 if line['card_id'] in decisions['starters'] else 0,
|
|
'win': 1 if line['card_id'] == decisions['winner'] else 0,
|
|
'loss': 1 if line['card_id'] == decisions['loser'] else 0,
|
|
'hold': 1 if line['card_id'] in decisions['holds'] else 0,
|
|
'sv': 1 if line['card_id'] == decisions['save'] else 0,
|
|
'bsv': 1 if line['card_id'] in decisions['b_save'] else 0,
|
|
'week': this_game.week_num,
|
|
'season': this_game.season,
|
|
'game_id': this_game.id
|
|
}
|
|
)
|
|
|
|
doubles += '\n' if len(doubles) else ''
|
|
triples += '\n' if len(triples) else ''
|
|
homers += '\n' if len(homers) else ''
|
|
s_bases += '\n' if len(s_bases) else ''
|
|
caught_s += '\n' if len(caught_s) else ''
|
|
|
|
db_post('batstats', payload={'stats': batter_stats})
|
|
db_post('pitstats', payload={'stats': pitcher_stats})
|
|
|
|
# Post a notification to PD
|
|
last_play = get_current_play(this_game.id)
|
|
inning = f'{last_play.inning_num if last_play.inning_half == "Bot" else last_play.inning_num - 1}'
|
|
embed = get_team_embed(
|
|
f'{away_team["lname"]} {away_stats["score"]} @ {home_stats["score"]} {home_team["lname"]} - F/'
|
|
f'{inning}',
|
|
winning_team
|
|
)
|
|
|
|
if this_game.game_type == 'major-league':
|
|
game_des = 'Major League'
|
|
elif this_game.game_type == 'minor-league':
|
|
game_des = 'Minor League'
|
|
elif this_game.ranked:
|
|
game_des = 'Ranked'
|
|
elif 'gauntlet' in this_game.game_type:
|
|
game_des = 'Gauntlet'
|
|
else:
|
|
game_des = 'Unlimited'
|
|
embed.description = f'Score Report - {game_des} ' \
|
|
f'{"- 3-Inning Game" if this_game.short_game else " - 9-Inning Game"}'
|
|
embed.add_field(
|
|
name='Box Score',
|
|
value=get_final_scorebug(away_team, home_team, away_stats, home_stats),
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name='Location',
|
|
value=f'{ctx.guild.get_channel(this_game.channel_id).mention}'
|
|
)
|
|
embed.add_field(
|
|
name='Pitching',
|
|
value=f'Win: {db_get("cards", object_id=decisions["winner"])["player"]["p_name"]}\n'
|
|
f'Loss: {db_get("cards", object_id=decisions["loser"])["player"]["p_name"]}\n'
|
|
f'{"Save: " if decisions["save"] else ""}'
|
|
f'{db_get("cards", object_id=decisions["save"])["player"]["p_name"] if decisions["save"] else ""}',
|
|
inline=False
|
|
)
|
|
if len(doubles) + len(triples) + len(homers) > 0:
|
|
embed.add_field(
|
|
name='Batting',
|
|
value=f'{"2B: " if len(doubles) else ""}{doubles if len(doubles) else ""}'
|
|
f'{"3B: " if len(triples) else ""}{triples if len(triples) else ""}'
|
|
f'{"HR: " if len(homers) else ""}{homers if len(homers) else ""}',
|
|
inline=False
|
|
)
|
|
if len(s_bases) + len(caught_s) > 0:
|
|
embed.add_field(
|
|
name='Baserunning',
|
|
value=f'{"SB: " if len(s_bases) else ""}{s_bases if len(s_bases) else ""}'
|
|
f'{"CSc: " if len(caught_s) else ""}{caught_s if len(caught_s) else ""}',
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name=f'{winning_team["abbrev"]} Rewards',
|
|
value=f'1x {win_reward["pack_type"]["name"]} Pack\n{win_reward["money"]}₼'
|
|
)
|
|
embed.add_field(
|
|
name=f'{losing_team["abbrev"]} Rewards',
|
|
value=f'{loss_reward["money"]}₼'
|
|
)
|
|
embed.add_field(
|
|
name='Highlights',
|
|
value=f'Please share the highlights in {get_channel(ctx, "pd-news-ticker").mention}!',
|
|
inline=False
|
|
)
|
|
await send_to_channel(self.bot, 'pd-network-news', embed=embed)
|
|
|
|
# Post rewards
|
|
give_packs(winning_team, num_packs=1, pack_type=win_reward['pack_type'])
|
|
db_post(f'teams/{winning_team["id"]}/money/{win_reward["money"]}')
|
|
db_post(f'teams/{losing_team["id"]}/money/{loss_reward["money"]}')
|
|
|
|
# Gauntlet results and reward
|
|
if gauntlet_team is not None:
|
|
await gauntlets.post_result(
|
|
int(this_game.game_type.split('-')[3]),
|
|
is_win=winning_team['gmid'] == gauntlet_team['gmid'],
|
|
this_team=gauntlet_team,
|
|
bot=self.bot,
|
|
ctx=ctx
|
|
)
|
|
|
|
else:
|
|
logging.debug(f'Time to build statlines and share the scorecard for this SBa game!')
|
|
# Send stats to sheets
|
|
# Post sheets link
|
|
pass
|
|
|
|
patch_game(this_game.id, active=False)
|
|
|
|
logging.info(f'Game {this_game.id} is complete')
|
|
if gauntlet_team is None:
|
|
await ctx.send(f'Good game! Go share the highlights in {get_channel(ctx, "pd-news-ticker").mention}!')
|
|
|
|
@app_commands.command(
|
|
name='readlineup',
|
|
description='Import a saved lineup directly from the team sheet for PD games'
|
|
)
|
|
@app_commands.describe(
|
|
team_abbrev='The 2- to 4-digit abbreviation for the team being set',
|
|
roster='Which roster to pull from your sheet?',
|
|
lineup='Which handedness lineup are you using?',
|
|
sp_card_id='Light gray number to the left of the pitcher\'s name on your depth chart'
|
|
)
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def read_lineup_command(
|
|
self, interaction: discord.Interaction, team_abbrev: str, roster: Literal['Primary', 'Secondary', 'Ranked'],
|
|
lineup: Literal['v Right', 'v Left'], sp_card_id: int):
|
|
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
|
|
|
|
if not this_game.is_pd:
|
|
await interaction.response.send_message(f'Lineup imports are only supported for PD games right now.'
|
|
f'Please use the `/setlineup` command.')
|
|
return
|
|
|
|
owner_team = await get_game_team(this_game, interaction.user.id)
|
|
if 'gauntlet' in this_game.game_type:
|
|
lineup_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}')
|
|
else:
|
|
lineup_team = await get_game_team(this_game, team_abbrev=team_abbrev)
|
|
|
|
if owner_team['gmid'] != lineup_team['gmid']:
|
|
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 try again'
|
|
)
|
|
return
|
|
|
|
existing_lineups = await get_team_lineups(this_game.id, lineup_team['id'])
|
|
if 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.send_message(f'Let\'s put this lineup card together...')
|
|
|
|
if lineup == 'v Right':
|
|
l_num = 1
|
|
else:
|
|
l_num = 2
|
|
|
|
if roster == 'Primary':
|
|
roster_num = 1
|
|
elif roster == 'Secondary':
|
|
roster_num = 2
|
|
else:
|
|
roster_num = 3
|
|
lineup_cells = get_roster_lineups(lineup_team, self.bot, roster_num, l_num)
|
|
|
|
all_lineups = []
|
|
all_pos = []
|
|
for index, row in enumerate(lineup_cells):
|
|
if '' in row:
|
|
break
|
|
|
|
if row[0].upper() not in all_pos:
|
|
all_pos.append(row[0].upper())
|
|
else:
|
|
raise SyntaxError(f'You have more than one {row[0].upper()} in this lineup. Please '
|
|
f'update and set the lineup again.')
|
|
|
|
this_card = db_get(f'cards', object_id=int(row[1]))
|
|
if this_card['team']['id'] != lineup_team['id']:
|
|
raise SyntaxError(f'Easy there, champ. Looks like card ID {row[1]} belongs to the '
|
|
f'{this_card["team"]["sname"]}. Try again with only cards you own.')
|
|
player_id = this_card['player']['player_id']
|
|
card_id = row[1]
|
|
|
|
this_lineup = {
|
|
'game_id': this_game.id,
|
|
'team_id': lineup_team['id'],
|
|
'player_id': player_id,
|
|
'card_id': card_id,
|
|
'position': row[0].upper(),
|
|
'batting_order': index + 1,
|
|
'after_play': 0
|
|
}
|
|
|
|
all_lineups.append(this_lineup)
|
|
|
|
if lineup_team['id'] == this_game.away_team_id:
|
|
patch_game(this_game.id, away_roster_num=roster_num)
|
|
else:
|
|
patch_game(this_game.id, home_roster_num=roster_num)
|
|
|
|
if lineup_team['is_ai']:
|
|
starter = starting_pitcher(lineup_team, self.bot, True if this_game.ai_team == 'home' else False)
|
|
this_card = db_get(f'cards', object_id=int(starter))
|
|
all_lineups.append({
|
|
'game_id': this_game.id,
|
|
'team_id': lineup_team['id'],
|
|
'player_id': this_card['player']['player_id'],
|
|
'card_id': starter,
|
|
'position': 'P',
|
|
'batting_order': 10,
|
|
'after_play': 0
|
|
})
|
|
all_pos.append('P')
|
|
else:
|
|
this_card = db_get(f'cards', object_id=sp_card_id)
|
|
logging.debug(f'this_card: {this_card}')
|
|
|
|
if this_card['team']['id'] != lineup_team['id']:
|
|
logging.error(
|
|
f'Card_id {sp_card_id} does not belong to {lineup_team["abbrev"]} in Game {this_game.id}'
|
|
)
|
|
await interaction.channel.send(
|
|
f'Uh oh. Card ID {sp_card_id} is {this_card["player"]["p_name"]} and belongs to '
|
|
f'{this_card["team"]["sname"]}. Will you double check that before we get started?')
|
|
return
|
|
|
|
else:
|
|
all_lineups.append({
|
|
'game_id': this_game.id,
|
|
'team_id': lineup_team['id'],
|
|
'player_id': this_card['player']['player_id'],
|
|
'card_id': sp_card_id,
|
|
'position': 'P',
|
|
'batting_order': 10,
|
|
'after_play': 0
|
|
})
|
|
all_pos.append('P')
|
|
|
|
logging.debug(f'Setting lineup for {lineup_team["sname"]} in PD game')
|
|
post_lineups(all_lineups)
|
|
|
|
# while True:
|
|
# # Get Starting Pitcher
|
|
# this_q = Question(
|
|
# self.bot, interaction.channel, f'Please enter the card_id of the {lineup_team["sname"]} SP',
|
|
# 'int', 45
|
|
# )
|
|
# resp = await this_q.ask([interaction.user])
|
|
#
|
|
# if not resp:
|
|
# await interaction.edit_original_response(
|
|
# content='Please enter the Starting Pitcher using the `/substitution` command'
|
|
# )
|
|
# return
|
|
# else:
|
|
|
|
if 'P' not in all_pos:
|
|
await interaction.channel.send(
|
|
content=f'Please enter the Starting pitcher using the `/starting-pitcher` command'
|
|
)
|
|
return
|
|
|
|
try:
|
|
await interaction.channel.send(content=None, embed=await self.get_game_state_embed(this_game))
|
|
except IntegrityError as e:
|
|
logging.debug(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.command(name='get-bullpen', help='Mod: Sync an AI bullpen')
|
|
@commands.is_owner()
|
|
async def get_bullpen_command(self, ctx: commands.Context, team_id):
|
|
team = db_get('teams', object_id=team_id)
|
|
if not team:
|
|
await ctx.send(f'I did not find a team with id {team_id}')
|
|
return
|
|
|
|
await ctx.send(f'I\'m getting bullpen data from {team["gmname"]}...')
|
|
get_or_create_bullpen(team, self.bot)
|
|
|
|
await ctx.send(f'Got it!')
|
|
|
|
@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(
|
|
order_number='Batting order of new player; 10 for pitchers if there is a DH',
|
|
new_player='For PD game: enter the Card ID (a number); or SBa game: enter the Player Name')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def substitution_command(
|
|
self, ctx: commands.Context, team_abbrev: str, new_player: str, order_number: Literal[
|
|
'this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
|
|
new_pos: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'PH', 'PR']):
|
|
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)
|
|
if 'gauntlet' in this_game.game_type:
|
|
lineup_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}')
|
|
else:
|
|
lineup_team = await get_game_team(this_game, team_abbrev=team_abbrev)
|
|
|
|
if owner_team['gmid'] != lineup_team['gmid']:
|
|
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
|
|
|
|
try:
|
|
if this_game.is_pd:
|
|
this_card = db_get(f'cards', object_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']['player_id']
|
|
card_id = new_player
|
|
else:
|
|
this_player = get_sba_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
|
|
except Exception as e:
|
|
logging.error(f'Game {this_game} - Could not find player {new_player}')
|
|
if this_game.is_pd:
|
|
await ctx.send(f'I could not find card_id {new_player}.')
|
|
else:
|
|
await ctx.send(f'I could not find {new_player.title()}.')
|
|
return
|
|
|
|
this_play = get_current_play(this_game.id)
|
|
batting_order = int(order_number) if order_number != 'this-spot' else this_play.batting_order
|
|
|
|
# Check for simple position change
|
|
in_lineup = get_one_lineup(this_game.id, team_id=lineup_team['id'], active=True, batting_order=batting_order)
|
|
if in_lineup.card_id == int(card_id):
|
|
post_pos = patch_lineup(in_lineup.id, position=new_pos)
|
|
else:
|
|
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.upper(),
|
|
'batting_order': batting_order,
|
|
'after_play': curr_play.play_num - 1 if curr_play else 0
|
|
}
|
|
|
|
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
|
|
|
|
response = await ctx.send(f'Building the scorebug now...')
|
|
|
|
await response.edit(content=None, embed=await self.get_game_state_embed(this_game, full_length=include_lineups))
|
|
|
|
async def checks_log_interaction(self, interaction: discord.Interaction, block_rollback: Optional[bool] = False) \
|
|
-> (Optional[StratGame], Optional[dict], Optional[StratPlay]):
|
|
await interaction.response.defer()
|
|
|
|
this_game = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if not this_game:
|
|
await interaction.edit_original_response(content='I don\'t see a game in this channel.')
|
|
return False, False, False
|
|
|
|
owner_team = await get_game_team(this_game, interaction.user.id)
|
|
if 'gauntlet' in this_game.game_type:
|
|
owner_team = await get_game_team(this_game, team_abbrev=f'Gauntlet-{owner_team["abbrev"]}')
|
|
if not owner_team['id'] in [this_game.away_team_id, this_game.home_team_id]:
|
|
logging.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} when they '
|
|
f'aren\'t a GM in the game.')
|
|
await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can log plays.')
|
|
# return this_game, False, False
|
|
|
|
this_play = get_current_play(this_game.id)
|
|
# Allow specific commands to not rollback the play (e.g. /show-card)
|
|
if this_play.locked and not block_rollback:
|
|
logging.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} while the '
|
|
f'play was locked.')
|
|
undo_play(this_play.id)
|
|
await interaction.edit_original_response(
|
|
content=f'Looks like your game got hung up there for a second. I just rolled it back a play to '
|
|
f'release it. If you have any more issues, let Cal know.'
|
|
)
|
|
this_play = get_current_play(this_game.id)
|
|
|
|
if not this_play.pitcher:
|
|
logging.info(f'{interaction.user.display_name} tried to run a command in Game {this_game.id} without a '
|
|
f'pitcher in the lineup.')
|
|
await interaction.edit_original_response(content=f'Please sub in a pitcher before logging a new play.')
|
|
this_play = None
|
|
|
|
return this_game, owner_team, this_play
|
|
|
|
group_log = app_commands.Group(name='log', description='Log a play in this channel\'s game')
|
|
|
|
@group_log.command(name='ai-pitcher-sub', description='Run automated substitution when the AI wants a change')
|
|
async def ai_pitcher_sub(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
away_team = await get_game_team(this_game, team_id=this_game.away_team_id)
|
|
home_team = await get_game_team(this_game, team_id=this_game.home_team_id)
|
|
ai_team = away_team if owner_team == home_team else home_team
|
|
|
|
if this_play.batter.team_id == ai_team['id']:
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like the {ai_team["sname"]} are batting now. If they need a sub, please do so when '
|
|
f'they are back on defense.'
|
|
)
|
|
return
|
|
|
|
curr_pitcher = get_one_lineup(this_game.id, team_id=ai_team['id'], position='P')
|
|
pit_plays = get_plays(this_game.id, curr_pitcher.id)
|
|
logging.debug(f'pit_plays for sub in Game {this_game.id}: {pit_plays}')
|
|
if pit_plays['count'] < 2:
|
|
pitcher = await get_player(this_game, curr_pitcher)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'It doesn\'t look like {pitcher["name"]} is fatigued - are you sure they should be subbed out?',
|
|
view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
await interaction.channel.send(
|
|
content=f'Thanks! I let {get_cal_user(interaction).mention} know there was an issue with '
|
|
f'{ai_team["abbrev"]} pitchers.'
|
|
)
|
|
else:
|
|
await question.delete()
|
|
await interaction.edit_original_response(content=f'Okay, I\'ll leave them in!')
|
|
return
|
|
|
|
# new_pitcher = await next_pitcher(this_play, ai_team, self.bot)
|
|
# logging.debug(f'new_pitcher: {new_pitcher}')
|
|
#
|
|
# this_lineup = {
|
|
# 'game_id': this_game.id,
|
|
# 'team_id': ai_team['id'],
|
|
# 'player_id': new_pitcher['player']['player_id'],
|
|
# 'card_id': new_pitcher['card_id'],
|
|
# 'position': 'P',
|
|
# 'batting_order': 10,
|
|
# 'after_play': this_play.play_num - 1
|
|
# }
|
|
# make_sub(this_lineup)
|
|
|
|
used_pitchers = await get_team_lineups(
|
|
game_id=this_play.game.id, team_id=ai_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
|
|
)
|
|
make_sub(ai_manager.get_relief_pitcher(this_play, ai_team, used_pitchers, this_game.game_type))
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game)
|
|
)
|
|
|
|
@group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c')
|
|
async def log_flyball(
|
|
self, interaction: discord.Interaction, flyball_type: Literal['a', 'b', 'ballpark', 'b?', 'c']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
await self.flyballs(interaction, this_game, this_play, flyball_type)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='groundball', description='Groundballs: a, b, c')
|
|
async def log_groundball(self, interaction: discord.Interaction, groundball_type: Literal['a', 'b', 'c']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
await self.groundballs(interaction, this_game, this_play, groundball_type)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='single', description='Singles: *, **, ballpark, uncapped')
|
|
async def log_single(
|
|
self, interaction: discord.Interaction, single_type: Literal['*', '**', 'ballpark', 'uncapped']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
if single_type == '**':
|
|
single_wellhit(this_play)
|
|
elif single_type == '*':
|
|
single_onestar(this_play)
|
|
elif single_type == 'ballpark':
|
|
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)
|
|
elif single_type == 'uncapped':
|
|
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
|
|
|
|
if this_play.on_base_code in [1, 2, 4, 5, 6, 7]:
|
|
ai_manager = get_manager(this_game)
|
|
ai_is_batting = ai_batting(this_game, this_play)
|
|
to_bases = [None, None, 'to second', 'to third', 'home']
|
|
at_bases = [None, None, 'at second', 'at third', 'at home']
|
|
|
|
if this_play.on_second:
|
|
lead_runner = await get_player(this_game, this_play.on_second)
|
|
lead_base = 4
|
|
if this_play.on_first:
|
|
trail_runner = await get_player(this_game, this_play.on_first)
|
|
trail_base = 3
|
|
else:
|
|
trail_runner = await get_player(this_game, this_play.batter)
|
|
trail_base = 2
|
|
else:
|
|
lead_runner = await get_player(this_game, this_play.on_first)
|
|
lead_base = 3
|
|
trail_runner = await get_player(this_game, this_play.batter)
|
|
trail_base = 2
|
|
|
|
ai_hint = ''
|
|
if this_game.ai_team and ai_is_batting:
|
|
ai_hint = f'*The runner will ' \
|
|
f'{ai_manager.uncapped_advance(lead_base, this_play.starting_outs)}*'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {lead_runner["name"]} being sent {to_bases[lead_base]}?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and not ai_is_batting:
|
|
ai_hint = f'*The defense will ' \
|
|
f'{ai_manager.throw_lead_runner(lead_base, this_play.starting_outs)}*'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is the defense throwing {to_bases[lead_base]}?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and ai_is_batting:
|
|
ai_hint = f'*The runner will ' \
|
|
f'{ai_manager.trail_advance(trail_base, this_play.starting_outs, True if lead_base == 4 else False)}*'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {trail_runner["name"]} being sent {to_bases[trail_base]}?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and not ai_is_batting:
|
|
ai_hint = f'*The defense will ' \
|
|
f'{ai_manager.throw_which_runner(lead_base, this_play.starting_outs)}*'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
view.confirm.label = 'Home Plate' if lead_base == 4 else 'Third Base'
|
|
view.cancel.label = 'Third Base' if trail_base == 3 else 'Second Base'
|
|
question = await interaction.channel.send(
|
|
f'Is the throw going {to_bases[lead_base]} or {to_bases[trail_base]}?\n\n{ai_hint}',
|
|
view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Throw to lead runner
|
|
if view.value:
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {lead_runner["name"]} thrown out {at_bases[lead_base]}?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 2)
|
|
batter_to_base = 2
|
|
if lead_base == 4:
|
|
patch_play(this_play.id, on_second_final=False, outs=1)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=False, outs=1)
|
|
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 2)
|
|
batter_to_base = 2
|
|
|
|
# Throw to trail runner
|
|
else:
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {trail_runner["name"]} thrown out {at_bases[trail_base]}?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 2)
|
|
if trail_base == 3:
|
|
patch_play(this_play.id, on_first_final=False, outs=1)
|
|
batter_to_base = 2
|
|
else:
|
|
patch_play(this_play.id, outs=1)
|
|
batter_to_base = None
|
|
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 2)
|
|
batter_to_base = 2
|
|
|
|
else:
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {lead_runner["name"]} thrown out at {to_bases[lead_base]}?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
if lead_base == 4:
|
|
patch_play(this_play.id, on_second_final=False, outs=1)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=False, outs=1)
|
|
|
|
else:
|
|
await question.delete()
|
|
advance_one_runner(this_play.id, from_base=lead_base - 2, num_bases=2)
|
|
|
|
else:
|
|
await question.delete()
|
|
advance_one_runner(this_play.id, from_base=lead_base - 2, num_bases=2)
|
|
|
|
else:
|
|
await question.delete()
|
|
|
|
logging.debug(f'post process batter runner on_second_final: {this_play.on_second_final}')
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='double', description='Doubles: **, ***, uncapped')
|
|
async def log_double(self, interaction: discord.Interaction, double_type: Literal['**', '***', 'uncapped']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
if double_type == '**':
|
|
double_twostar(this_play)
|
|
elif double_type == '***':
|
|
double_threestar(this_play)
|
|
elif double_type == 'uncapped':
|
|
advance_runners(this_play.id, 2)
|
|
this_play = patch_play(this_play.id, locked=True, pa=1, ab=1, hit=1, double=1)
|
|
|
|
batter_to_base = 2
|
|
ai_is_batting = ai_batting(this_game, this_play)
|
|
ai_manager = get_manager(this_game)
|
|
|
|
if this_play.on_first:
|
|
ai_hint = ''
|
|
if this_game.ai_team and ai_is_batting:
|
|
if this_play.on_first:
|
|
ai_hint = f'*The runner will attempt to advance*'
|
|
else:
|
|
ai_hint = f'*The runner will ' \
|
|
f'{ai_manager.uncapped_advance(4, this_play.starting_outs)}*'
|
|
|
|
runner_to_home = await get_player(this_game, this_play.on_first)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {runner_to_home["name"]} being sent home?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and not ai_is_batting:
|
|
ai_hint = f'*The defense will {ai_manager.throw_lead_runner(4, this_play.starting_outs)}*'
|
|
|
|
# Throw for lead runner?
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is the defense throwing home?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Yes: Send Trail runner?
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and ai_is_batting:
|
|
ai_hint = f'*The trail runner will ' \
|
|
f'{ai_manager.trail_advance(3, this_play.starting_outs, True)}*'
|
|
|
|
batter_runner = await get_player(this_game, this_play.batter)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {batter_runner["name"]} being sent to third?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Yes: Throw lead or trail?
|
|
if view.value:
|
|
await question.delete()
|
|
ai_hint = ''
|
|
if this_game.ai_team and not ai_is_batting:
|
|
ai_hint = f'*The defense will ' \
|
|
f'{ai_manager.throw_which_runner(4, this_play.starting_outs)}*'
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
view.confirm.label = 'Home Plate'
|
|
view.cancel.label = 'Third Base'
|
|
question = await interaction.channel.send(
|
|
f'Is the throw going to home plate or to third base?\n\n{ai_hint}', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Throw home
|
|
if view.value:
|
|
batter_to_base = 3
|
|
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {runner_to_home["name"]} thrown out at the plate?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Out at the plate
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(this_play.id, on_first_final=False, outs=1)
|
|
|
|
# Safe at the plate
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, 3)
|
|
|
|
# Throw to third
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, num_bases=3)
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {batter_runner["name"]} thrown out at third?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Out at third
|
|
if view.value:
|
|
await question.delete()
|
|
batter_to_base = None
|
|
advance_runners(this_play.id, num_bases=3)
|
|
patch_play(this_play.id, outs=1)
|
|
|
|
# Safe at home and third
|
|
else:
|
|
await question.delete()
|
|
|
|
# No: Safe at home?
|
|
else:
|
|
await question.delete()
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
content=f'Was {runner_to_home["name"]} thrown out at the plate?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
# Out at the plate
|
|
if view.value:
|
|
await question.delete()
|
|
patch_play(this_play.id, on_first_final=False, outs=1)
|
|
|
|
# Safe at the plate
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, num_bases=3)
|
|
|
|
# No: End of play
|
|
else:
|
|
await question.delete()
|
|
advance_runners(this_play.id, num_bases=3)
|
|
else:
|
|
await question.delete()
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='triple', description='Triples: no sub-types')
|
|
async def log_triple(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
triple(this_play)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='homerun', description='Home Runs: ballpark, no-doubt')
|
|
async def log_homerun(self, interaction: discord.Interaction, homerun_type: Literal['ballpark', 'no-doubt']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
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)
|
|
if homerun_type == 'ballpark':
|
|
patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1, bphr=1)
|
|
elif homerun_type == 'no-doubt':
|
|
patch_play(this_play.id, pa=1, ab=1, hit=1, homerun=1)
|
|
complete_play(this_play.id, batter_to_base=4)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='walk', description='Walks: unintentional, intentional')
|
|
async def log_walk(self, interaction: discord.Interaction, walk_type: Literal['unintentional', 'intentional']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
|
|
if walk_type == 'unintentional':
|
|
patch_play(this_play.id, pa=1, walk=1)
|
|
elif walk_type == 'intentional':
|
|
patch_play(this_play.id, pa=1, ibb=1)
|
|
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='chaos', description='Chaos: wild-pitch, passed-ball, balk, pickoff')
|
|
async def log_chaos(self, interaction: discord.Interaction,
|
|
chaos_type: Literal['wild-pitch', 'passed-ball', 'balk', 'pickoff']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
if chaos_type == 'wild-pitch':
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, wp=1)
|
|
elif chaos_type == 'passed-ball':
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, pb=1)
|
|
elif chaos_type == 'balk':
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, balk=1)
|
|
elif chaos_type == 'pickoff':
|
|
# Get from base
|
|
runner_flag = False
|
|
patch_play(this_play.id, pick=1)
|
|
|
|
if this_play.on_base_code in [1, 2, 3]:
|
|
if this_play.on_first:
|
|
patch_play(this_play.id, on_first_final=False, runner_id=this_play.on_first.id, outs=1)
|
|
elif this_play.on_second:
|
|
patch_play(this_play.id, on_second_final=False, runner_id=this_play.on_second.id, outs=1)
|
|
elif this_play.on_third:
|
|
patch_play(this_play.id, on_third_final=False, runner_id=this_play.on_third.id, outs=1)
|
|
|
|
else:
|
|
if this_play.on_first:
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(f'Was {this_runner["name"]} picked off?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
patch_play(this_play.id, on_first_final=False, runner_id=this_play.on_first.id, outs=1)
|
|
runner_flag = True
|
|
|
|
await question.delete()
|
|
|
|
if this_play.on_second and not runner_flag:
|
|
this_runner = await get_player(this_game, this_play.on_second)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(f'Was {this_runner["name"]} picked off?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
patch_play(this_play.id, on_second_final=False, runner_id=this_play.on_second.id, outs=1)
|
|
runner_flag = True
|
|
|
|
await question.delete()
|
|
|
|
if this_play.on_third and not runner_flag:
|
|
this_runner = await get_player(this_game, this_play.on_third)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(f'Was {this_runner["name"]} picked off?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
patch_play(this_play.id, on_third_final=False, runner_id=this_play.on_third.id, outs=1)
|
|
runner_flag = True
|
|
|
|
await question.delete()
|
|
|
|
if not runner_flag:
|
|
await interaction.edit_original_response(content=f'So I guess nobody got picked off?')
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
complete_play(this_play.id)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='stealing', description='Running: stolen-base, caught-stealing')
|
|
@app_commands.describe(to_base='Base the runner is advancing to; 2 for 2nd, 3 for 3rd, 4 for Home')
|
|
async def log_stealing(
|
|
self, interaction: discord.Interaction,
|
|
running_type: Literal['stolen-base', 'caught-stealing', 'steal-plus-overthrow'],
|
|
to_base: Literal[2, 3, 4]):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
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'
|
|
)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
if running_type == 'stolen-base':
|
|
if to_base == 'Home' 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 to_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 interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at third.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
elif to_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 interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at second.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=f'Uh oh - I don\'t see a runner there to steal the bag.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
if running_type == 'steal-plus-overthrow':
|
|
if to_base == 'Home' 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 to_base == 3 and this_play.on_second:
|
|
advance_runners(this_play.id, 1)
|
|
if not this_play.on_third:
|
|
patch_play(
|
|
this_play.id, sb=1, on_second_final=4, runner_id=this_play.on_second.id, catcher_id=catcher.id
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_second)
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at third.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
elif to_base == 2 and this_play.on_first:
|
|
if not this_play.on_second:
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(
|
|
this_play.id, sb=1, on_first_final=3, runner_id=this_play.on_first.id, catcher_id=catcher.id
|
|
)
|
|
else:
|
|
this_runner = await get_player(this_game, this_play.on_first)
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at second.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=f'Uh oh - I don\'t see a runner there to steal the bag.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
patch_play(this_play.id, error=1)
|
|
|
|
elif running_type == 'caught-stealing':
|
|
if to_base == 'Home' and this_play.on_third:
|
|
patch_play(
|
|
this_play.id, cs=1, on_third_final=False, runner_id=this_play.on_third.id,
|
|
catcher_id=catcher.id, outs=1
|
|
)
|
|
elif to_base == 3 and this_play.on_second:
|
|
if not this_play.on_third:
|
|
patch_play(
|
|
this_play.id, cs=1, on_second_final=False, 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 interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at third.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
elif to_base == 2 and this_play.on_first:
|
|
if not this_play.on_second:
|
|
patch_play(
|
|
this_play.id, cs=1, on_first_final=False, 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 interaction.edit_original_response(
|
|
content=f'Ope. Looks like {this_runner["name"]} is blocked by the runner at second.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=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 interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='strikeout', description='Strikeout')
|
|
async def log_strikeout(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1, so=1)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
complete_play(this_play.id)
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='popout', description='Popout')
|
|
async def log_popout(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
complete_play(this_play.id)
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@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']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=True)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
if lineout_type == 'one-out' or this_play.starting_outs == 2 or this_play.on_base_code == 0:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
|
|
elif lineout_type == 'ballpark':
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1, bplo=1)
|
|
|
|
elif lineout_type == 'max-outs':
|
|
bases = ['third', 'second', 'first']
|
|
num_outs = 1
|
|
|
|
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=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {runner["name"]} out at {bases[count]} on the play?', 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)
|
|
patch_play(this_play.id, pa=1, ab=1, outs=num_outs)
|
|
|
|
complete_play(this_play.id)
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='hit-by-pitch', description='Batter to first; runners advance if forced')
|
|
async def log_hit_by_pitch_command(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
|
|
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 interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='sac-bunt', description='Batter out; runners advance one base')
|
|
async def log_sac_bunt_command(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
|
|
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 interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='undo-play', description='Remove the most recent play from the log')
|
|
async def log_undo_play_command(self, interaction: discord.Interaction):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
|
|
try:
|
|
logging.debug(f'Undoing play {this_play.id} in Game {this_game.id}: Batter {this_play.batter}')
|
|
undo_play(this_game.id)
|
|
except AttributeError as e:
|
|
logging.error(f'Could not undo play {this_play.id} in game {this_game.id}')
|
|
|
|
try:
|
|
last_completed = get_latest_play(this_game.id)
|
|
logging.debug(f'Undoing play {last_completed.id} in Game {this_game.id}')
|
|
undo_play(this_game.id)
|
|
|
|
latest_play = get_latest_play(this_game.id)
|
|
logging.debug(f'Latest completed play is Play {latest_play.id}; batter_to_base: {latest_play.batter_final}')
|
|
except AttributeError as e:
|
|
logging.error(f'Could not undo second play in game {this_game.id}')
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='xcheck', description='Defender makes an x-check')
|
|
@app_commands.choices(position=[
|
|
Choice(name='Pitcher', value='P'),
|
|
Choice(name='Catcher', value='C'),
|
|
Choice(name='First Base', value='1B'),
|
|
Choice(name='Second Base', value='2B'),
|
|
Choice(name='Third Base', value='3B'),
|
|
Choice(name='Shortstop', value='SS'),
|
|
Choice(name='Left Field', value='LF'),
|
|
Choice(name='Center Field', value='CF'),
|
|
Choice(name='Right Field', value='RF'),
|
|
])
|
|
async def log_xcheck_command(self, interaction: discord.Interaction, position: Choice[str]):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
|
|
def_team_id = this_game.away_team_id if this_play.inning_half == 'Bot' else this_game.home_team_id
|
|
def_team = db_get('teams', object_id=def_team_id)
|
|
d_lineup = get_one_lineup(this_game.id, team_id=this_play.pitcher.team_id, position=position.value)
|
|
defender = await get_player(this_game, d_lineup)
|
|
patch_play(this_play.id, defender_id=d_lineup.id, check_pos=position.value)
|
|
|
|
defender_embed = get_team_embed(f'{def_team["sname"]} {position.value}', def_team)
|
|
defender_embed.description = f'{defender["name"]}'
|
|
defender_embed.set_image(url=defender['image'])
|
|
embeds = [defender_embed]
|
|
|
|
dice_embeds = sa_fielding_roll(position.value, def_team)
|
|
embeds.extend(dice_embeds)
|
|
all_embeds = [x for x in embeds if x is not None]
|
|
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embeds=all_embeds
|
|
)
|
|
|
|
hit_allowed, error_allowed, chaos_allowed = None, None, None
|
|
|
|
if position.value == 'C':
|
|
view = Confirm([interaction.user], label_type='yes')
|
|
question = await interaction.channel.send(f'Did {defender["name"]} give up a chaos result?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view = ButtonOptions(responders=[interaction.user], labels=['WP', 'X (PB)', None, None, None])
|
|
question = await interaction.channel.send(
|
|
f'Which chaos result did {defender["name"]} allow?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value == 'WP' or view.value == 'X (PB)':
|
|
await question.delete()
|
|
if view.value == 'WP':
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, wp=1)
|
|
elif view.value == 'X (PB)':
|
|
advance_runners(this_play.id, 1)
|
|
patch_play(this_play.id, rbi=0, pb=1)
|
|
|
|
complete_play(this_play.id)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
else:
|
|
await question.delete()
|
|
|
|
else:
|
|
await question.delete()
|
|
|
|
view = Confirm([interaction.user], label_type='yes')
|
|
question = await interaction.channel.send(f'Did {defender["name"]} give up a hit?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['single*', 'single**', 'double**', 'double***', 'triple']
|
|
)
|
|
question = await interaction.channel.send(f'Which hit did {defender["name"]} allow?', view=view)
|
|
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.edit(f'Hmm...you keep thinking on it and get back to me when you\'re ready.')
|
|
return
|
|
else:
|
|
await question.delete()
|
|
|
|
hit_allowed = view.value
|
|
else:
|
|
await question.delete()
|
|
hit_allowed = 'out'
|
|
|
|
view = Confirm([interaction.user], label_type='yes')
|
|
question = await interaction.channel.send(f'Did {defender["name"]} give up an error?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['1 base', '2 bases', '3 bases', None, None]
|
|
)
|
|
question = await interaction.channel.send(f'How many bases did {defender["name"]} allow?', view=view)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.edit(f'Hmm...you keep thinking on it and get back to me when you\'re ready.')
|
|
return
|
|
else:
|
|
await question.delete()
|
|
|
|
error_allowed = view.value
|
|
else:
|
|
await question.delete()
|
|
error_allowed = 'no error'
|
|
|
|
# Not hit and no error
|
|
if hit_allowed == 'out' and error_allowed == 'no error':
|
|
if position.value not in ['LF', 'CF', 'RF']:
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['gb A', 'gb B', 'gb C', None if position.value != 'C' else 'FO',
|
|
None if position.value != 'C' else 'PO']
|
|
)
|
|
question = await interaction.channel.send(f'What was the result of the play?', view=view)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.delete()
|
|
|
|
if view.value == 'gb A':
|
|
await self.groundballs(interaction, this_game, this_play, groundball_type='a')
|
|
elif view.value == 'gb B':
|
|
await self.groundballs(interaction, this_game, this_play, groundball_type='b')
|
|
elif view.value == 'gb C':
|
|
await self.groundballs(interaction, this_game, this_play, groundball_type='c')
|
|
else:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 0)
|
|
complete_play(this_play.id)
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
else:
|
|
await question.delete()
|
|
if view.value in ['FO', 'PO']:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 0)
|
|
complete_play(this_play.id)
|
|
|
|
else:
|
|
if view.value == 'gb A':
|
|
gb_code = 'a'
|
|
elif view.value == 'gb B':
|
|
gb_code = 'b'
|
|
else:
|
|
gb_code = 'c'
|
|
|
|
await self.groundballs(interaction, this_game, this_play, gb_code)
|
|
|
|
else:
|
|
view = ButtonOptions(responders=[interaction.user], labels=['fly A', 'fly B', 'fly C', None, None])
|
|
question = await interaction.channel.send(f'What was the result of the play?', view=view)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.delete()
|
|
await interaction.channel.send(
|
|
content=f'Just logged the x-check! Please log the resulting play to continue (e.g. '
|
|
f'\'flyball-b\' or \'flyball-c\')'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
else:
|
|
await question.delete()
|
|
if view.value == 'fly A':
|
|
fly_code = 'a'
|
|
elif view.value == 'fly B':
|
|
fly_code = 'b'
|
|
else:
|
|
fly_code = 'c'
|
|
|
|
await self.flyballs(interaction, this_game, this_play, fly_code)
|
|
|
|
# Hit and error
|
|
elif hit_allowed != 'out' and error_allowed != 'no error':
|
|
patch_play(this_play.id, error=1)
|
|
if hit_allowed == 'triple':
|
|
triple(this_play, comp_play=False)
|
|
advance_runners(this_play.id, num_bases=4)
|
|
batter_to_base = 4
|
|
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:
|
|
advance_runners(this_play.id, 3)
|
|
batter_to_base = 3
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
# Either hit or error
|
|
else:
|
|
num_bases = None
|
|
if error_allowed == 'no error':
|
|
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:
|
|
patch_play(this_play.id, error=1)
|
|
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)
|
|
|
|
patch_play(this_play.id, locked=False)
|
|
await interaction.channel.send(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
# @group_log.command(name='xcheck', description='Defender makes an x-check')
|
|
# async def log_xcheck_command(self, interaction: discord.Interaction, position: Literal[
|
|
# 'Pitcher', '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['no error', '1 base', '2 bases', '3 bases']):
|
|
# this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
# if False in (this_game, owner_team, this_play):
|
|
# return
|
|
#
|
|
# patch_play(this_play.id, locked=False)
|
|
#
|
|
# pos = get_pos_abbrev(position)
|
|
# defender = get_one_lineup(
|
|
# this_game.id, team_id=this_play.pitcher.team_id, position=pos
|
|
# )
|
|
# logging.info(f'defender: {defender}')
|
|
# patch_play(this_play.id, defender_id=defender.id, error=1 if error_allowed != 'no-error' else 0, check_pos=pos)
|
|
#
|
|
# # Not hit and no error
|
|
# if hit_allowed == 'out' and error_allowed == 'no error':
|
|
# await interaction.edit_original_response(
|
|
# content=f'Just logged the x-check! Please log the resulting play to continue (e.g. \'flyball-b\' or '
|
|
# f'\'groundball-a\')'
|
|
# )
|
|
# patch_play(this_play.id, locked=False)
|
|
# return
|
|
#
|
|
# # Hit and error
|
|
# elif hit_allowed != 'out' and error_allowed != 'no error':
|
|
# if hit_allowed == 'triple':
|
|
# triple(this_play, comp_play=False)
|
|
# batter_to_base = 4
|
|
# 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
|
|
# else:
|
|
# num_bases = None
|
|
# if error_allowed == 'no error':
|
|
# 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)
|
|
#
|
|
# patch_play(this_play.id, locked=False)
|
|
# await interaction.edit_original_response(
|
|
# content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
# )
|
|
|
|
group_show = app_commands.Group(name='show-card', description='Display the player card for an active player')
|
|
|
|
@group_show.command(name='defense', description='Display a defender\'s player card')
|
|
async def show_defense_command(
|
|
self, interaction: discord.Interaction, position: 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_interaction(interaction, block_rollback=True)
|
|
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=IMAGES['logo'])
|
|
|
|
await interaction.edit_original_response(content=None, embed=embed)
|
|
|
|
@group_show.command(name='lineup', description='Display a batting team member\'s player card')
|
|
async def show_batting_team_command(
|
|
self, interaction: discord.Interaction, batting_order: Optional[int] = None,
|
|
relative_order: Optional[Literal['on-deck', 'in-the-hole']] = None):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
if batting_order:
|
|
lineup_member = get_one_lineup(
|
|
this_game.id, team_id=this_play.batter.team_id, batting_order=batting_order
|
|
)
|
|
elif relative_order:
|
|
modifier = 1 if relative_order == 'on-deck' else 2
|
|
b_order = this_play.batter.batting_order + modifier
|
|
if b_order == 10:
|
|
b_order = 1
|
|
if b_order == 11:
|
|
b_order = 2
|
|
lineup_member = get_one_lineup(
|
|
this_game.id, team_id=this_play.batter.team_id, batting_order=b_order
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=f'You need to select either a batting order or relative order.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
|
|
this_player = await get_player(game=this_game, lineup_member=lineup_member)
|
|
|
|
embed = get_team_embed(f'{this_player["team"]["sname"]} #{lineup_member.batting_order} Batter',
|
|
this_player['team'])
|
|
embed.description = f'{this_player["name"]}'
|
|
embed.set_image(url=this_player['image'])
|
|
if this_game.is_pd:
|
|
embed.set_footer(text=f'PD Season {PD_SEASON}', icon_url=IMAGES['logo'])
|
|
|
|
await interaction.edit_original_response(content=None, embed=embed)
|
|
|
|
@commands.command(name='load-ai', hidden=True)
|
|
@commands.is_owner()
|
|
async def load_ai_command(self, ctx):
|
|
await ctx.send(f'{load_ai()}')
|
|
|
|
# @commands.command(name='pentest', hidden=True)
|
|
# @commands.is_owner()
|
|
# async def pen_test_command(self, ctx, team_id: int = 3):
|
|
# this_pen = get_or_create_bullpen({'id': team_id}, self.bot)
|
|
# await ctx.send(f'{this_pen}')
|
|
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(Gameplay(bot))
|