4417 lines
208 KiB
Python
4417 lines
208 KiB
Python
import asyncio
|
|
import logging
|
|
import math
|
|
import copy
|
|
import os
|
|
|
|
import ai_manager
|
|
import discord
|
|
|
|
import dice
|
|
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, get_role, player_desc, player_pcard, player_bcard
|
|
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_fielding_stats, get_pitching_decisions, get_or_create_bullpen, get_active_games, patch_lineup, \
|
|
get_last_game_ids, get_plays, get_manager, get_one_game, load_ai, ai_batting, undo_subs, get_dbready_plays, \
|
|
convert_stratlineup
|
|
|
|
|
|
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=3)
|
|
async def live_scoreboard(self):
|
|
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
|
score_channel = discord.utils.get(guild.text_channels, name='live-pd-scores')
|
|
player_role = discord.utils.get(guild.roles, name=PD_PLAYERS_ROLE_NAME)
|
|
|
|
active_games = get_active_games(6)
|
|
if len(active_games) == 0:
|
|
await score_channel.set_permissions(player_role, read_messages=False)
|
|
return
|
|
|
|
try:
|
|
embed = get_team_embed('Live Scoreboard')
|
|
valid_scores = False
|
|
for x in active_games:
|
|
await asyncio.sleep(1)
|
|
gs = await self.get_game_state(x)
|
|
if not gs['error']:
|
|
valid_scores = True
|
|
channel = guild.get_channel(gs["channel_id"])
|
|
g_message = gs['scorebug']
|
|
g_message += f'Pitcher: {gs["pitcher"]["p_name"]}\n' \
|
|
f'Batter: {gs["batter"]["p_name"]}\n' \
|
|
f'Location: {channel.mention if channel is not None else "Your Butt"}\n' \
|
|
f'-------------------------'
|
|
gt_string = 'Unlimited'
|
|
if x.game_type == 'minor-league':
|
|
gt_string = 'Minor League'
|
|
elif x.game_type == 'major-league':
|
|
gt_string = 'Major League'
|
|
elif x.game_type == 'hall-of-fame':
|
|
gt_string = 'Hall of Fame'
|
|
elif 'gauntlet' in x.game_type:
|
|
gt_string = 'Gauntlet'
|
|
elif x.game_type == 'flashback':
|
|
gt_string = 'Flashback'
|
|
embed.add_field(
|
|
name=f'{gs["away_team"]["sname"]} @ {gs["home_team"]["sname"]} - {gt_string}',
|
|
value=g_message,
|
|
inline=False
|
|
)
|
|
|
|
if valid_scores:
|
|
async for message in score_channel.history(limit=25):
|
|
await message.delete()
|
|
|
|
await score_channel.set_permissions(player_role, read_messages=True)
|
|
await score_channel.send(content=None, embed=embed)
|
|
else:
|
|
await score_channel.set_permissions(player_role, read_messages=False)
|
|
return
|
|
except Exception as e:
|
|
logging.error(f'Could not update live_scoreboard: {e}')
|
|
|
|
@live_scoreboard.before_loop
|
|
async def before_live_scoreboard(self):
|
|
await self.bot.wait_until_ready()
|
|
|
|
@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[:1600]}')
|
|
|
|
async def post_stratgame(self, this_game: StratGame, forfeit: bool = False):
|
|
return await db_post('games', payload={
|
|
'season': this_game.season,
|
|
'game_type': this_game.game_type,
|
|
'away_team_id': this_game.away_team_id,
|
|
'home_team_id': this_game.home_team_id,
|
|
'week': this_game.week_num,
|
|
'ranked': this_game.ranked,
|
|
'short_game': this_game.short_game,
|
|
'forfeit': forfeit
|
|
})
|
|
|
|
async def post_allplays(self, this_game: StratGame, final_game_id: int):
|
|
all_plays = get_dbready_plays(this_game.id, db_game_id=final_game_id)
|
|
await asyncio.sleep(0.5)
|
|
return await db_post(
|
|
'plays',
|
|
payload={'plays': all_plays},
|
|
timeout=15
|
|
)
|
|
|
|
async def post_decisions(self, this_game: StratGame, final_game_id: int):
|
|
all_dec = get_pitching_decisions(this_game, final_game_id)
|
|
await asyncio.sleep(0.5)
|
|
return await db_post(
|
|
'decisions',
|
|
payload={'decisions': all_dec},
|
|
timeout=5
|
|
)
|
|
|
|
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 post_rewards(self, winning_team: dict, losing_team: dict, this_game: StratGame):
|
|
wr_query = await db_get(
|
|
'gamerewards', params=[('name', f'{"Short" if this_game.short_game else "Full"} Game Win')])
|
|
lr_query = await 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.')
|
|
|
|
human_team = winning_team if losing_team['is_ai'] else losing_team
|
|
ai_team = winning_team if winning_team['is_ai'] else losing_team
|
|
|
|
win_reward = wr_query['gamerewards'][0]
|
|
loss_reward = lr_query['gamerewards'][0]
|
|
win_string = f'1x {win_reward["pack_type"]["name"]} Pack\n'
|
|
|
|
# Post Team Choice packs
|
|
if this_game.ai_team is not None and not this_game.short_game and 'gauntlet' not in this_game.game_type and \
|
|
losing_team['is_ai']:
|
|
g_query = await db_get(
|
|
'games',
|
|
params=[
|
|
('team1_id', human_team['id']), ('game_type', this_game.game_type), ('season', this_game.season)
|
|
]
|
|
)
|
|
wins = 0
|
|
for x in g_query['games']:
|
|
if (x['away_score'] > x['home_score'] and x['away_team']['id'] == human_team['id']) or (
|
|
x['home_score'] > x['away_score'] and x['home_team']['id'] == human_team['id']):
|
|
wins += 1
|
|
|
|
async def post_tc_pack():
|
|
await db_post(
|
|
'packs/one',
|
|
payload={
|
|
'team_id': human_team['id'],
|
|
'pack_type_id': 8,
|
|
'pack_team_id': losing_team['id']
|
|
}
|
|
)
|
|
|
|
if g_query['count'] > 0:
|
|
if this_game.game_type == 'minor-league' and wins % 6 == 0:
|
|
await post_tc_pack()
|
|
win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n'
|
|
elif this_game.game_type == 'major-league' and wins % 4 == 0:
|
|
await post_tc_pack()
|
|
win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n'
|
|
elif this_game.game_type == 'hall-of-fame' and wins % 2 == 0:
|
|
await post_tc_pack()
|
|
win_string += f'1x {losing_team["abbrev"]} Team Choice pack\n'
|
|
|
|
win_string += f'{win_reward["money"]}₼\n'
|
|
loss_string = f'{loss_reward["money"]}₼\n'
|
|
|
|
# Post rewards
|
|
if 'gauntlet' in this_game.game_type:
|
|
if 'Gauntlet' in winning_team['abbrev']:
|
|
t_query = await db_get('teams', params=[('abbrev', winning_team['abbrev'].split('-')[1])])
|
|
winning_team = t_query['teams'][0]
|
|
if 'Gauntlet' in losing_team['abbrev']:
|
|
t_query = await db_get('teams', params=[('abbrev', losing_team['abbrev'].split('-')[1])])
|
|
losing_team = t_query['teams'][0]
|
|
|
|
await give_packs(winning_team, num_packs=1, pack_type=win_reward['pack_type'])
|
|
await db_post(f'teams/{winning_team["id"]}/money/{win_reward["money"]}')
|
|
await db_post(f'teams/{losing_team["id"]}/money/{loss_reward["money"]}')
|
|
|
|
data = {
|
|
'win_string': win_string,
|
|
'loss_string': loss_string
|
|
}
|
|
|
|
return data
|
|
|
|
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)
|
|
logging.info(f'away_lineup: {away_lineup}')
|
|
logging.info(f'home_lineup: {home_lineup}')
|
|
|
|
if len(away_lineup) < 200 or len(home_lineup) < 200:
|
|
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.debug(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}
|
|
|
|
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
|
|
|
|
if curr_play.inning_half == 'Top':
|
|
game_state['pitcher']['team'] = home_team
|
|
game_state['catcher']['team'] = home_team
|
|
game_state['batter']['team'] = away_team
|
|
else:
|
|
game_state['pitcher']['team'] = away_team
|
|
game_state['catcher']['team'] = away_team
|
|
game_state['batter']['team'] = home_team
|
|
logging.debug(f'game_state: {game_state}')
|
|
|
|
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}')
|
|
|
|
gt_string = ' - Unlimited'
|
|
if game.game_type == 'minor-league':
|
|
gt_string = ' - Minor League'
|
|
elif game.game_type == 'major-league':
|
|
gt_string = ' - Major League'
|
|
elif game.game_type == 'hall-of-fame':
|
|
gt_string = ' - Hall of Fame'
|
|
elif 'gauntlet' in game.game_type:
|
|
gt_string = ' - Gauntlet'
|
|
elif 'flashback' in game.game_type:
|
|
gt_string = ' - Flashback'
|
|
|
|
embed = discord.Embed(
|
|
title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}',
|
|
color=int(SBA_COLOR, 16)
|
|
)
|
|
logging.debug(f'got embed')
|
|
|
|
if game.is_pd:
|
|
footer_text = f'Paper Dynasty 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
|
|
|
|
logging.debug(f'no errors')
|
|
embed.add_field(name='Game State', value=game_state['scorebug'], inline=False)
|
|
|
|
logging.debug(f'check mercy')
|
|
if abs(game_state['curr_play'].home_score - game_state['curr_play'].away_score) >= 10:
|
|
embed.description = '***Mercy rule in effect***'
|
|
# embed.color = discord.Colour.red()
|
|
|
|
logging.debug(f'set pitcher string')
|
|
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}'
|
|
|
|
logging.debug(f'pull bat stats')
|
|
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}'
|
|
|
|
logging.debug(f'pull pitcher stats')
|
|
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***'
|
|
|
|
logging.debug(f'set embed pitcher/batter')
|
|
# 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_image(url=player_bcard(game_state['batter']))
|
|
|
|
logging.debug(f'get baserunners')
|
|
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'
|
|
|
|
logging.debug(f'set baserunners')
|
|
if len(baserunner_string) > 0:
|
|
embed.add_field(name=' ', value=' ', inline=False)
|
|
embed.add_field(
|
|
name='Baserunners', value=baserunner_string
|
|
)
|
|
embed.add_field(
|
|
name='Catcher', value=f'{player_link(game, game_state["catcher"])}'
|
|
)
|
|
else:
|
|
embed.add_field(
|
|
name='Baserunners', value='None', inline=False
|
|
)
|
|
|
|
logging.debug(f'do AI stuff')
|
|
# 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']:
|
|
ai_data = await ai_manager.pitching_ai_note(game_state['curr_play'], game_state['pitcher'])
|
|
logging.debug(f'ai_data: {ai_data}')
|
|
ai_note = ai_data['note']
|
|
gm_name = ai_data['gm_name']
|
|
embed.set_thumbnail(url=player_pcard(ai_data['pitcher']))
|
|
|
|
if ai_data['sub'] is not None:
|
|
embed.add_field(
|
|
name='SUBSTITUTION',
|
|
value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in '
|
|
f'{player_desc(ai_data["sub"])} to pitch'
|
|
)
|
|
|
|
# AI Team is batting
|
|
elif game_state['batter']['team']['is_ai']:
|
|
embed.set_thumbnail(url=player_pcard(game_state["pitcher"]))
|
|
ai_data = ai_manager.batting_ai_note(game_state['curr_play'], game_state['batter'])
|
|
ai_note = ai_data['note']
|
|
gm_name = ai_data['gm_name']
|
|
|
|
if ai_note:
|
|
embed.add_field(
|
|
name=f'{gm_name} will...',
|
|
value=ai_note,
|
|
inline=False
|
|
)
|
|
|
|
logging.debug(f'if not full length: return embed: {embed}')
|
|
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_old(
|
|
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["p_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["p_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["p_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["p_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["p_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["p_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["p_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["p_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["p_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["p_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["p_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["p_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 groundballs(
|
|
self, interaction, this_game, this_play: StratPlay, groundball_type: str, comp_play: bool = True):
|
|
batter_to_base = None
|
|
|
|
if this_play.starting_outs == 2 or this_play.on_base_code == 0:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
|
|
elif this_play.starting_outs == 1 and groundball_type == 'a' and this_play.on_base_code == 1:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=2, on_first_final=False)
|
|
|
|
else:
|
|
playing_in = False
|
|
if runner_on_third(this_play):
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the defender playing in?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
playing_in = True
|
|
else:
|
|
playing_in = False
|
|
|
|
await question.delete()
|
|
logging.info(f'playing_in: {playing_in} / obc: {this_play.on_base_code} / gb_type: {groundball_type}')
|
|
|
|
if not playing_in:
|
|
if groundball_type == 'a':
|
|
if this_play.on_base_code == 0:
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
elif this_play.on_base_code in [1, 4, 5, 7]:
|
|
batter_to_base = gb_result_2(this_play)
|
|
|
|
elif this_play.on_base_code in [3, 6]:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the ball hit to either the 2B or SS?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
to_mif = True
|
|
else:
|
|
to_mif = False
|
|
await question.delete()
|
|
|
|
batter_to_base = gb_result_5(this_play, to_mif)
|
|
|
|
else:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the ball hit to either the 1B or 2B?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
to_right_side = True
|
|
else:
|
|
to_right_side = False
|
|
await question.delete()
|
|
batter_to_base = gb_result_6(this_play, to_right_side)
|
|
|
|
elif groundball_type == 'b':
|
|
if this_play.on_base_code == 0:
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
elif this_play.on_base_code in [1, 4, 5, 7]:
|
|
batter_to_base = gb_result_4(this_play)
|
|
|
|
elif this_play.on_base_code in [3, 6]:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the ball hit to either the 2B or SS?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
to_mif = True
|
|
else:
|
|
to_mif = False
|
|
await question.delete()
|
|
|
|
batter_to_base = gb_result_5(this_play, to_mif)
|
|
|
|
else:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the ball hit to either the 1B or 2B?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
to_right_side = True
|
|
else:
|
|
to_right_side = False
|
|
await question.delete()
|
|
batter_to_base = gb_result_6(this_play, to_right_side)
|
|
|
|
else:
|
|
if this_play.on_base_code == 0:
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
else:
|
|
batter_to_base = gb_result_3(this_play)
|
|
|
|
else:
|
|
if groundball_type == 'a':
|
|
if this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_10(this_play)
|
|
else:
|
|
batter_to_base = gb_result_7(this_play)
|
|
|
|
elif groundball_type == 'b':
|
|
if this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_11(this_play)
|
|
elif this_play.on_base_code == 5:
|
|
batter_to_base = gb_result_9(this_play)
|
|
else:
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
else:
|
|
if this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_11(this_play)
|
|
else:
|
|
batter_to_base = gb_result_8(this_play)
|
|
|
|
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:
|
|
logging.debug(f'calling of embed')
|
|
await show_outfield_cards(interaction, this_play)
|
|
logging.debug(f'done with of embed')
|
|
|
|
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["p_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["p_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:
|
|
logging.debug(f'calling of embed')
|
|
await show_outfield_cards(interaction, this_play)
|
|
logging.debug(f'done with of embed')
|
|
|
|
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["p_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["p_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)
|
|
|
|
group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game')
|
|
|
|
@group_new_game.command(name='mlb-campaign', description='Start a new MLB Campaign game against an AI')
|
|
@app_commands.describe(
|
|
sp_card_id='Light gray number to the left of the pitcher\'s name on your depth chart')
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_campaign_command(
|
|
self, interaction: discord.Interaction,
|
|
league: Literal['Minor League', 'Flashback', 'Major League', 'Hall of Fame'],
|
|
away_team_abbrev: str, home_team_abbrev: str, num_innings: Literal[9, 3], sp_card_id: 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
|
|
|
|
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 = await get_team_by_abbrev(away_team_abbrev)
|
|
home_team = await 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 = await 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
|
|
human_team = away_team if home_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 'Flashback' 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 completed the Minor League campaign, yet!\n\n'
|
|
f'To play **Flashback** 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 = 'flashback'
|
|
|
|
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:
|
|
can_play = False
|
|
for x in interaction.user.roles:
|
|
if x.name == 'PD - Hall of Fame':
|
|
can_play = True
|
|
|
|
if not can_play:
|
|
await interaction.edit_original_response(
|
|
content=f'Ope. Looks like you haven\'t received the **PD - Hall of Fame** role, yet!\n\n'
|
|
f'To play **Hall of Fame** games, you need to defeat all 30 MLB teams in the Minor League '
|
|
f'and Major League campaign. You can see your progress with `/record`.\n\n'
|
|
f'If you have completed the Major League campaign, go ping Cal to get your new role!')
|
|
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} ({league_name}) between {away_team_abbrev.upper()} and '
|
|
f'{home_team_abbrev.upper()} is posted!'
|
|
)
|
|
away_role = await team_role(interaction, away_team)
|
|
home_role = await team_role(interaction, home_team)
|
|
all_lineups = []
|
|
|
|
# Get Human SP
|
|
human_sp_card = await db_get(f'cards', object_id=sp_card_id)
|
|
|
|
if human_sp_card['team']['id'] != human_team['id']:
|
|
logging.error(
|
|
f'Card_id {sp_card_id} does not belong to {human_team["abbrev"]} in Game {this_game.id}'
|
|
)
|
|
patch_game(this_game.id, active=False)
|
|
await interaction.channel.send(
|
|
f'Uh oh. Card ID {sp_card_id} is {human_team["player"]["p_name"]} and belongs to '
|
|
f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?')
|
|
return
|
|
|
|
if this_game.game_type in ['major-league', 'hall-of-fame']:
|
|
l_check = await legal_check([human_sp_card['id']], 'ranked')
|
|
if not l_check['legal']:
|
|
patch_game(this_game.id, active=False)
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a Ranked Legal game and {player_desc(human_sp_card["player"])} is '
|
|
f'not legal in Ranked. You can start a new game once you pick a new SP.'
|
|
)
|
|
return
|
|
|
|
if this_game.game_type == 'flashback':
|
|
l_check = await legal_check([human_sp_card['id']], 'flashback')
|
|
if not l_check['legal']:
|
|
patch_game(this_game.id, active=False)
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a Flashback game and {player_desc(human_sp_card["player"])} is '
|
|
f'not legal in Flashback. You can start a new game once you pick a new SP.'
|
|
)
|
|
return
|
|
|
|
all_lineups.append({
|
|
'game_id': this_game.id,
|
|
'team_id': human_team['id'],
|
|
'player_id': human_sp_card['player']['player_id'],
|
|
'card_id': sp_card_id,
|
|
'position': 'P',
|
|
'batting_order': 10,
|
|
'after_play': 0
|
|
})
|
|
|
|
# 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 = await ai_manager.get_starting_pitcher(
|
|
ai_team,
|
|
this_game.id,
|
|
True if home_team['is_ai'] else False,
|
|
league_name
|
|
)
|
|
all_lineups.append(starter)
|
|
ai_sp = await db_get('players', object_id=starter['player_id'])
|
|
|
|
this_card = await db_get(f'cards', object_id=starter['card_id'])
|
|
await interaction.channel.send(
|
|
content=f'The {ai_team["sname"]} are starting **{player_desc(this_card["player"])}**:\n\n'
|
|
f'{player_pcard(this_card["player"])}'
|
|
)
|
|
|
|
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
|
|
|
|
# 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"]}')
|
|
batters = await ai_manager.build_lineup(
|
|
ai_team, this_game.id, league_name, sp_name=ai_sp['p_name']
|
|
)
|
|
all_lineups.extend(batters)
|
|
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
|
|
|
|
logging.debug(f'Setting lineup for {ai_team["sname"]} in PD game')
|
|
logging.debug(f'lineups: {all_lineups}')
|
|
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 `/read-lineup` 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 = await get_team_by_abbrev(away_team_abbrev)
|
|
home_team = await 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 = await 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 `/read-lineup` 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 = await get_team_by_abbrev(away_team_abbrev)
|
|
home_team = await 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 = await 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 `/read-lineup` 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['Taste of 2018'], sp_card_id: 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
|
|
|
|
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 = await db_get('current')
|
|
week_num = current['week']
|
|
|
|
e_query = await 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 = await get_team_by_owner(interaction.user.id)
|
|
team = await 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 = await db_get(
|
|
'gauntletruns',
|
|
params=[('team_id', team['id']), ('gauntlet_id', this_event['id']), ('is_active', True)]
|
|
)
|
|
|
|
if r_query['count'] == 0:
|
|
await interaction.edit_original_response(
|
|
content=f'I don\'t see an active run for you. If you would like to start a new one, run '
|
|
f'`/gauntlets start {this_event["name"]}` and we can get you started in no time!'
|
|
)
|
|
return
|
|
|
|
this_run = r_query['runs'][0]
|
|
|
|
# If not new or after draft, create new AI game
|
|
is_home = gauntlets.is_home_team(team, this_event, this_run)
|
|
opponent = await 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)
|
|
|
|
all_lineups = []
|
|
# Get Human SP
|
|
human_sp_card = await db_get(f'cards', object_id=sp_card_id)
|
|
|
|
if human_sp_card['team']['id'] != team['id']:
|
|
logging.error(
|
|
f'Card_id {sp_card_id} does not belong to {team["abbrev"]} in Game {this_game.id}'
|
|
)
|
|
await interaction.channel.send(
|
|
f'Uh oh. Card ID {sp_card_id} is {team["player"]["p_name"]} and belongs to '
|
|
f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?')
|
|
return
|
|
|
|
if this_game.game_type in ['major-league', 'hall-of-fame']:
|
|
l_check = await legal_check([human_sp_card['id']])
|
|
if not l_check['legal']:
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a Ranked Legal game and {player_desc(human_sp_card["player"])} is '
|
|
f'not legal in Ranked. You can start a new game once you get a new SP.'
|
|
)
|
|
return
|
|
|
|
all_lineups.append({
|
|
'game_id': this_game.id,
|
|
'team_id': team['id'],
|
|
'player_id': human_sp_card['player']['player_id'],
|
|
'card_id': sp_card_id,
|
|
'position': 'P',
|
|
'batting_order': 10,
|
|
'after_play': 0
|
|
})
|
|
|
|
# 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 = await gauntlets.get_starting_pitcher(opponent, this_game, this_event, this_run)
|
|
all_lineups.append(starter)
|
|
ai_sp = await db_get('players', object_id=starter['player_id'])
|
|
|
|
this_card = await db_get(f'cards', object_id=starter['card_id'])
|
|
await interaction.channel.send(
|
|
content=f'The {opponent["sname"]} are starting **{player_desc(this_card["player"])}**:\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
|
|
|
|
# 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"]}')
|
|
batters = await gauntlets.build_lineup(opponent, this_game, this_event, ai_sp["p_name"])
|
|
all_lineups.extend(batters)
|
|
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
|
|
|
|
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 `/read-lineup` 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())
|
|
|
|
@app_commands.command(name='end-game', description='End game in this channel')
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def end_game_command(self, interaction: discord.Interaction):
|
|
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='Ope, I don\'t see a game in this channel.')
|
|
return
|
|
logging.info(f'Ending Game {this_game.id}')
|
|
|
|
response = await interaction.edit_original_response(content=f'Let\'s see what we\'ve got here...')
|
|
|
|
owner_team = await get_game_team(this_game, interaction.user.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 interaction.edit_original_response(content='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 \
|
|
interaction.user.id != self.bot.owner_id:
|
|
await interaction.edit_original_response(content='Bruh. Only GMs of the active teams can end games.')
|
|
return
|
|
|
|
latest_play = get_latest_play(this_game.id)
|
|
|
|
if latest_play is None:
|
|
await self.post_stratgame(this_game, forfeit=True)
|
|
await send_to_channel(
|
|
self.bot, 'pd-network-news',
|
|
f'The **{owner_team["lname"]}** made an oopsie-poopsie and had to call off their game down in '
|
|
f'{interaction.channel.mention}')
|
|
this_game = patch_game(this_game.id, active=False)
|
|
await interaction.edit_original_response(
|
|
content='Roger dodger - it is game over.'
|
|
)
|
|
return
|
|
|
|
valid_end = False
|
|
logging.debug(f'latest play: {latest_play}')
|
|
if not this_game.short_game:
|
|
if latest_play.starting_outs == 0:
|
|
logging.debug(f'no outs')
|
|
if latest_play.inning_half.lower() == 'top':
|
|
logging.debug(f'top of inning')
|
|
if latest_play.inning_num > 9 and latest_play.away_score != latest_play.home_score:
|
|
logging.debug(f'after the ninth and not tied')
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logging.debug(f'not after ninth, but mercy')
|
|
valid_end = True
|
|
if latest_play.inning_half.lower() == 'bot':
|
|
if (latest_play.home_score > latest_play.away_score) and latest_play.inning_num >= 9:
|
|
logging.debug(f'bottom half and home team winning')
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logging.debug(f'bottom half and mercy')
|
|
valid_end = True
|
|
elif abs(latest_play.home_score - latest_play.away_score) >= 10 and latest_play.inning_half.lower() == 'bot':
|
|
logging.info(f'bottom half and it is a mercy')
|
|
valid_end = True
|
|
elif latest_play.inning_num >= 9 and latest_play.inning_half.lower() == 'bot' and \
|
|
latest_play.home_score > latest_play.away_score:
|
|
valid_end = True
|
|
else:
|
|
if latest_play.starting_outs == 0:
|
|
logging.debug(f'no outs')
|
|
if latest_play.inning_half.lower() == 'top':
|
|
logging.debug(f'top of inning')
|
|
if latest_play.inning_num > 3 and latest_play.away_score != latest_play.home_score:
|
|
logging.debug(f'after the ninth and not tied')
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logging.debug(f'not after ninth, but mercy')
|
|
valid_end = True
|
|
if latest_play.inning_half.lower() == 'bot':
|
|
if (latest_play.home_score > latest_play.away_score) and latest_play.inning_num >= 3:
|
|
logging.debug(f'bottom half and home team winning')
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logging.debug(f'bottom half and mercy')
|
|
valid_end = True
|
|
elif abs(latest_play.home_score - latest_play.away_score) >= 10 and latest_play.inning_half.lower() == 'bot':
|
|
logging.info(f'bottom half and it is a mercy')
|
|
valid_end = True
|
|
elif latest_play.inning_num >= 3 and latest_play.inning_half.lower() == 'bot' and \
|
|
latest_play.home_score > latest_play.away_score:
|
|
valid_end = True
|
|
|
|
# valid_end = True # TODO: REMOVE THIS BEFORE GO-LIVE
|
|
if not valid_end:
|
|
view = Confirm(responders=[interaction.user])
|
|
question = await interaction.channel.send(
|
|
'It doesn\'t look like this game is over, yet. I can end it, but no rewards will be paid out and '
|
|
'you will take the L.\n\n'
|
|
'Should I end this game?',
|
|
view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()# New database driven stat submission
|
|
failure = False
|
|
final_game = await self.post_stratgame(this_game)
|
|
|
|
# Send Plays to db
|
|
try:
|
|
resp = await self.post_allplays(this_game, final_game['id'])
|
|
if not resp:
|
|
failure = True
|
|
except Exception as e:
|
|
logging.error(f'end-game - Could not post plays: {e}')
|
|
failure = True
|
|
|
|
# Send Decisions to db
|
|
try:
|
|
resp = await self.post_decisions(this_game, final_game['id'])
|
|
if not resp:
|
|
failure = True
|
|
except Exception as e:
|
|
logging.error(f'end-game - Could not post decisions: {e}')
|
|
failure = True
|
|
|
|
if failure:
|
|
try:
|
|
await db_delete(f'decisions/game', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete decisions')
|
|
|
|
try:
|
|
await db_delete(f'plays/game', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete plays')
|
|
|
|
try:
|
|
await db_delete(f'games', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete game')
|
|
|
|
await interaction.channel.send(
|
|
content=f'That did not go well and I wasn\'t able to submit this game. I recommend pinging Cal so he '
|
|
f'can fix this.'
|
|
)
|
|
return
|
|
|
|
await send_to_channel(
|
|
self.bot, 'pd-network-news',
|
|
f'The **{owner_team["lname"]}** had to cut out early from their game down in '
|
|
f'{interaction.channel.mention}')
|
|
this_game = patch_game(this_game.id, active=False)
|
|
await interaction.edit_original_response(
|
|
content='Roger dodger - it is game over.'
|
|
)
|
|
return
|
|
|
|
else:
|
|
await question.edit(
|
|
content='It stays.', view=None
|
|
)
|
|
return
|
|
|
|
await response.edit(content=None, embed=await self.get_game_state_embed(this_game, full_length=False))
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.edit_original_response(content=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
|
|
|
|
# New database driven stat submission
|
|
failure = False
|
|
final_game = await self.post_stratgame(this_game)
|
|
|
|
# Send Plays to db
|
|
try:
|
|
resp = await self.post_allplays(this_game, final_game['id'])
|
|
if not resp:
|
|
failure = True
|
|
except Exception as e:
|
|
logging.error(f'end-game - Could not post plays: {e}')
|
|
failure = True
|
|
|
|
# Send Decisions to db
|
|
try:
|
|
resp = await self.post_decisions(this_game, final_game['id'])
|
|
if not resp:
|
|
failure = True
|
|
except Exception as e:
|
|
logging.error(f'end-game - Could not post decisions: {e}')
|
|
failure = True
|
|
|
|
if failure:
|
|
try:
|
|
await db_delete(f'decisions/game', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete decisions')
|
|
|
|
try:
|
|
await db_delete(f'plays/game', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete plays')
|
|
|
|
try:
|
|
await db_delete(f'games', object_id=final_game["id"])
|
|
except Exception as e:
|
|
logging.error(f'could not delete game')
|
|
|
|
await interaction.channel.send(
|
|
content=f'That did not go well and I wasn\'t able to submit this game. I recommend pinging Cal so he '
|
|
f'can fix this.'
|
|
)
|
|
return
|
|
|
|
gs = await db_get(f'plays/game-summary/{final_game["id"]}')
|
|
await db_patch('games', object_id=gs['game']['id'],
|
|
params=[('away_score', gs['runs']['away']), ('home_score', gs['runs']['home'])])
|
|
|
|
away_team = gs['teams']['away']
|
|
home_team = gs['teams']['home']
|
|
winning_team = away_team if latest_play.away_score > latest_play.home_score else home_team
|
|
losing_team = away_team if latest_play.away_score < latest_play.home_score else home_team
|
|
|
|
# Post Game Rewards
|
|
r_data = await self.post_rewards(winning_team, losing_team, this_game)
|
|
win_reward = r_data['win_string']
|
|
loss_reward = r_data['loss_string']
|
|
|
|
# Post a notification to PD
|
|
logging.debug(f'getting inning')
|
|
inning = f'{latest_play.inning_num if latest_play.inning_half == "Bot" else latest_play.inning_num - 1}'
|
|
embed = get_team_embed(
|
|
f'{away_team["lname"]} {latest_play.away_score} @ {latest_play.home_score} {home_team["lname"]} - F/'
|
|
f'{inning}',
|
|
winning_team
|
|
)
|
|
|
|
logging.debug(f'setting location')
|
|
embed.add_field(
|
|
name='Location',
|
|
value=f'{interaction.guild.get_channel(this_game.channel_id).mention}'
|
|
)
|
|
|
|
embed.add_field(name='Game ID', value=f'{final_game["id"]}')
|
|
|
|
logging.debug(f'getting league name')
|
|
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.game_type == 'hall-of-fame':
|
|
game_des = 'Hall of Fame'
|
|
elif this_game.game_type == 'flashback':
|
|
game_des = 'Flashback'
|
|
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"}'
|
|
logging.debug(f'building box score')
|
|
embed.add_field(
|
|
name='Box Score',
|
|
value=f'```\n'
|
|
f'Team | R | H | E |\n'
|
|
f'{away_team["abbrev"].replace("Gauntlet-", ""): <4} | {gs["runs"]["away"]: >2} | '
|
|
f'{gs["hits"]["away"]: >2} | {gs["errors"]["away"]: >2} |\n'
|
|
f'{home_team["abbrev"].replace("Gauntlet-", ""): <4} | {gs["runs"]["home"]: >2} | '
|
|
f'{gs["hits"]["home"]: >2} | {gs["errors"]["home"]: >2} |\n'
|
|
f'\n```',
|
|
inline=False
|
|
)
|
|
|
|
logging.debug(f'getting potg string')
|
|
tp = gs["top-players"][0]
|
|
potg_string = f'{player_desc(tp["player"])} - '
|
|
if 'hr' in tp:
|
|
potg_string += f'{tp["hit"]}-{tp["ab"]}'
|
|
if tp['hr'] > 0:
|
|
num = f'{tp["hr"]} ' if tp["hr"] > 1 else ""
|
|
potg_string += f', {num}HR'
|
|
if tp['triple'] > 0:
|
|
num = f'{tp["triple"]} ' if tp["triple"] > 1 else ""
|
|
potg_string += f', {num}3B'
|
|
if tp['double'] > 0:
|
|
num = f'{tp["double"]} ' if tp["double"] > 1 else ""
|
|
potg_string += f', {num}2B'
|
|
if tp['run'] > 0:
|
|
potg_string += f', {tp["run"]} R'
|
|
if tp['rbi'] > 0:
|
|
potg_string += f', {tp["rbi"]} RBI'
|
|
else:
|
|
potg_string = f'{player_desc(tp["player"])} - {tp["ip"]} IP, {tp["run"]} R'
|
|
if tp['run'] != tp['e_run']:
|
|
potg_string += f' ({tp["e_run"]} ER)'
|
|
potg_string += f', {tp["hit"]} H, {tp["so"]} K'
|
|
potg_string += f', {tp["re24"]:.2f} re24'
|
|
embed.add_field(
|
|
name='Player of the Game',
|
|
value=potg_string,
|
|
inline=False
|
|
)
|
|
|
|
logging.info(f'potg: {potg_string}')
|
|
logging.debug(f'getting pitcher string')
|
|
pit_string = f'Win: {gs["pitchers"]["win"]["p_name"]}\n' \
|
|
f'Loss: {gs["pitchers"]["loss"]["p_name"]}\n'
|
|
if gs['pitchers']['save'] is not None:
|
|
pit_string += f'Save: {player_desc(gs["pitchers"]["save"])}'
|
|
embed.add_field(
|
|
name=f'Pitching',
|
|
value=pit_string,
|
|
)
|
|
|
|
def name_list(raw_list: list) -> str:
|
|
logging.info(f'raw_list: {raw_list}')
|
|
player_dict = {}
|
|
for x in raw_list:
|
|
if x['player_id'] not in player_dict:
|
|
player_dict[x['player_id']] = x
|
|
|
|
data_dict = {}
|
|
for x in raw_list:
|
|
if x['player_id'] not in data_dict:
|
|
data_dict[x['player_id']] = 1
|
|
else:
|
|
data_dict[x['player_id']] += 1
|
|
|
|
r_string = ''
|
|
logging.info(f'players: {player_dict} / data: {data_dict}')
|
|
|
|
first = True
|
|
for p_id in data_dict:
|
|
r_string += f'{", " if not first else ""}{player_dict[p_id]["p_name"]}'
|
|
if data_dict[p_id] > 1:
|
|
r_string += f' {data_dict[p_id]}'
|
|
first = False
|
|
|
|
return r_string
|
|
|
|
logging.info(f'getting running string')
|
|
if len(gs['running']['sb']) + len(gs['running']['csc']) > 0:
|
|
run_string = ''
|
|
if len(gs['running']['sb']) > 0:
|
|
run_string += f'SB: {name_list(gs["running"]["sb"])}\n'
|
|
|
|
if len(gs['running']['csc']) > 0:
|
|
run_string += f'CSc: {name_list(gs["running"]["csc"])}'
|
|
|
|
embed.add_field(
|
|
name=f'Baserunning',
|
|
value=run_string
|
|
)
|
|
|
|
logging.info(f'getting xbh string')
|
|
if len(gs['xbh']['2b']) + len(gs['xbh']['3b']) + len(gs['xbh']['hr']) > 0:
|
|
bat_string = ''
|
|
if len(gs['xbh']['2b']) > 0:
|
|
bat_string += f'2B: {name_list(gs["xbh"]["2b"])}\n'
|
|
|
|
if len(gs['xbh']['3b']) > 0:
|
|
bat_string += f'3B: {name_list(gs["xbh"]["3b"])}\n'
|
|
|
|
if len(gs['xbh']['hr']) > 0:
|
|
bat_string += f'HR: {name_list(gs["xbh"]["hr"])}\n'
|
|
else:
|
|
bat_string = 'Oops! All bitches! No XBH from either team.'
|
|
|
|
logging.info(f'building embed')
|
|
embed.add_field(
|
|
name='Batting',
|
|
value=bat_string,
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name=f'{winning_team["abbrev"]} Rewards',
|
|
value=win_reward
|
|
)
|
|
embed.add_field(
|
|
name=f'{losing_team["abbrev"]} Rewards',
|
|
value=loss_reward
|
|
)
|
|
embed.add_field(
|
|
name='Highlights',
|
|
value=f'Please share the highlights in {get_channel(interaction, "pd-news-ticker").mention}!',
|
|
inline=False
|
|
)
|
|
logging.info(f'sending scorebug')
|
|
await send_to_channel(self.bot, 'pd-network-news', embed=embed)
|
|
|
|
# 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,
|
|
channel=interaction.channel
|
|
)
|
|
|
|
this_run = await db_get('gauntletruns', object_id=int(this_game.game_type.split('-')[3]))
|
|
if this_run['losses'] == 2:
|
|
await send_to_channel(
|
|
bot=self.bot,
|
|
channel_name='pd-network-news',
|
|
content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the '
|
|
f'{this_run["gauntlet"]["name"]} gauntlet.',
|
|
embed=None
|
|
)
|
|
|
|
patch_game(this_game.id, active=False)
|
|
|
|
logging.info(f'Game {this_game.id} is complete')
|
|
if gauntlet_team is None:
|
|
await interaction.channel.send(
|
|
content=f'Good game! Go share the highlights in '
|
|
f'{get_channel(interaction, "pd-news-ticker").mention}!'
|
|
)
|
|
|
|
"""
|
|
END OF THE NEW GAME END
|
|
"""
|
|
|
|
# away_team = await db_get('teams', object_id=this_game.away_team_id)
|
|
# home_team = await 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 interaction.edit_original_response(
|
|
# content=f'I was not able to process stats for {bad_player["name"]} - '
|
|
# f'{get_cal_user(interaction).mention} 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 interaction.edit_original_response(
|
|
# content=f'I was not able to process stats for {bad_player["name"]} - '
|
|
# f'{get_cal_user(interaction).mention} 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 interaction.edit_original_response(
|
|
# content=f'I was not able to calculate the Winning and Losing Pitcher for this game. Is the game '
|
|
# f'ending early? {get_cal_user(interaction).mention} can probably help.'
|
|
# )
|
|
# return
|
|
# logging.debug(f'decisions: {decisions}')
|
|
#
|
|
# 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
|
|
#
|
|
# # Post Game Rewards
|
|
# r_data = await self.post_rewards(winning_team, losing_team, this_game)
|
|
# win_reward = r_data['win_string']
|
|
# loss_reward = r_data['loss_string']
|
|
#
|
|
# # 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}')
|
|
#
|
|
# logging.debug(f'Time to build statlines and submit the scorecard for this PD game!')
|
|
# # Post result
|
|
# success = await 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 += ', '
|
|
# card = await db_get("cards", object_id=line["card_id"])
|
|
# doubles += f'{card["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 += ', '
|
|
# card = await db_get("cards", object_id=line["card_id"])
|
|
# triples += f'{card["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 += ', '
|
|
# card = await db_get("cards", object_id=line["card_id"])
|
|
# homers += f'{card["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 += ', '
|
|
# card = await db_get("cards", object_id=line["card_id"])
|
|
# s_bases += f'{card["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 += ', '
|
|
# card = await db_get("cards", object_id=line["card_id"])
|
|
# caught_s += f'{card["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 ''
|
|
#
|
|
# await db_post('batstats', payload={'stats': batter_stats})
|
|
# await 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.game_type == 'hall-of-fame':
|
|
# game_des = 'Hall of Fame'
|
|
# 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'{interaction.guild.get_channel(this_game.channel_id).mention}'
|
|
# )
|
|
# wc_query = await db_get("cards", object_id=decisions["winner"])
|
|
# lc_query = await db_get("cards", object_id=decisions["loser"])
|
|
# if decisions["save"]:
|
|
# sv_query = await db_get("cards", object_id=decisions["save"])
|
|
# embed.add_field(
|
|
# name='Pitching',
|
|
# value=f'Win: {wc_query["player"]["p_name"]}\n'
|
|
# f'Loss: {lc_query["player"]["p_name"]}\n'
|
|
# f'{"Save: " if decisions["save"] else ""}'
|
|
# f'{sv_query["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=win_reward
|
|
# )
|
|
# embed.add_field(
|
|
# name=f'{losing_team["abbrev"]} Rewards',
|
|
# value=loss_reward
|
|
# )
|
|
# embed.add_field(
|
|
# name='Highlights',
|
|
# value=f'Please share the highlights in {get_channel(interaction, "pd-news-ticker").mention}!',
|
|
# inline=False
|
|
# )
|
|
# await send_to_channel(self.bot, 'pd-network-news', embed=embed)
|
|
#
|
|
# # 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,
|
|
# channel=interaction.channel
|
|
# )
|
|
#
|
|
# this_run = await db_get('gauntletruns', object_id=int(this_game.game_type.split('-')[3]))
|
|
# if this_run['losses'] == 2:
|
|
# await send_to_channel(
|
|
# bot=self.bot,
|
|
# channel_name='pd-network-news',
|
|
# content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the '
|
|
# f'{this_run["gauntlet"]["name"]} gauntlet.',
|
|
# embed=None
|
|
# )
|
|
#
|
|
# patch_game(this_game.id, active=False)
|
|
#
|
|
# logging.info(f'Game {this_game.id} is complete')
|
|
# if gauntlet_team is None:
|
|
# await interaction.edit_original_response(
|
|
# content=f'Good game! Go share the highlights in '
|
|
# f'{get_channel(interaction, "pd-news-ticker").mention}!'
|
|
# )
|
|
|
|
@app_commands.command(
|
|
name='read-lineup',
|
|
description='Import a saved lineup directly from the team sheet for PD games'
|
|
)
|
|
@app_commands.describe(
|
|
roster='Which roster to pull from your sheet?',
|
|
lineup='Which handedness lineup are you using?'
|
|
)
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def read_lineup_command(
|
|
self, interaction: discord.Interaction, roster: Literal['Primary', 'Secondary', 'Ranked'],
|
|
lineup: Literal['v Right', 'v Left']):
|
|
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
|
|
|
|
lineup_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-{lineup_team["abbrev"]}')
|
|
if not lineup_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 pull lineups.')
|
|
return
|
|
|
|
existing_lineups = await get_team_lineups(this_game.id, lineup_team['id'], as_string=False)
|
|
if len(existing_lineups) > 1:
|
|
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 = []
|
|
card_ids = []
|
|
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 = await db_get(f'cards', object_id=int(row[1]))
|
|
if this_card is None:
|
|
raise LookupError(
|
|
f'Your {row[0].upper()} has a Card ID or {int(row[1])} and I cannot find that card. Did you sell '
|
|
f'that card by chance? Or did you sell a duplicate and the bot sold the one you were using?'
|
|
)
|
|
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]
|
|
card_ids.append(str(card_id))
|
|
|
|
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)
|
|
|
|
# Check roster legality
|
|
if this_game.game_type in ['major-league', 'hall-of-fame']:
|
|
l_check = await legal_check(card_ids, 'ranked')
|
|
if not l_check['legal']:
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a Ranked Legal game and I see the following cards as illegal. '
|
|
f'Please adjust your lineup and re-submit!\n\n'
|
|
f'- {l_check["error_string"]}'
|
|
)
|
|
return
|
|
|
|
if this_game.game_type == 'flashback':
|
|
l_check = await legal_check(card_ids, 'flashback')
|
|
if not l_check['legal']:
|
|
patch_game(this_game.id, active=False)
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a Flashback game and I see the following cards as illegal. '
|
|
f'Please adjust your lineup and re-submit!\n\n'
|
|
f'- {l_check["error_string"]}'
|
|
)
|
|
return
|
|
|
|
logging.debug(f'Setting lineup for {lineup_team["sname"]} in PD game')
|
|
post_lineups(all_lineups)
|
|
|
|
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 = await 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!')
|
|
|
|
group_substitution = app_commands.Group(name='substitute', description='Make a substitution in active game')
|
|
|
|
@group_substitution.command(name='batter', description='Make a batter substitution')
|
|
@app_commands.describe(
|
|
batting_order='Batting order of new player',
|
|
new_player='Enter the Card ID (a number)')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME)
|
|
async def sub_batter_command(
|
|
self, interaction: discord.Interaction, new_player: int, batting_order: Literal[
|
|
'this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
|
|
new_pos: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'PH', 'PR']):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
this_card = await db_get(f'cards', object_id=int(new_player))
|
|
if this_card["team"]["id"] != owner_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
|
|
|
|
if this_game.game_type in ['major-league', 'hall-of-fame', 'tens']:
|
|
legality = await db_post(f'cards/legal-check/{this_game.game_type}?card_id={new_player}')
|
|
if legality['count'] > 0:
|
|
il_string = "\n- ".join(legality['bad_cards'])
|
|
await interaction.edit_original_response(
|
|
content=f'It looks like this is a {this_game.game_type.replace("-", " ").title()} game and I see '
|
|
f'the following cards as illegal. Please take another look and re-submit!\n\n'
|
|
f'- {il_string}'
|
|
)
|
|
return
|
|
|
|
batting_order = int(batting_order) if batting_order != 'this-spot' else this_play.batting_order
|
|
|
|
# Check for simple position change
|
|
in_lineup = get_one_lineup(this_game.id, team_id=owner_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:
|
|
this_lineup = {
|
|
'game_id': this_game.id,
|
|
'team_id': owner_team['id'],
|
|
'player_id': player_id,
|
|
'card_id': card_id,
|
|
'position': new_pos.upper(),
|
|
'batting_order': batting_order,
|
|
'after_play': this_play.play_num - 1 if this_play else 0
|
|
}
|
|
|
|
make_sub(this_lineup)
|
|
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game)
|
|
)
|
|
|
|
@group_substitution.command(name='pitcher', description='Make a pitching change')
|
|
@app_commands.describe(
|
|
new_player='Enter the Card ID (a number)',
|
|
batting_order='Only enter this if you are forfeiting the DH')
|
|
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME)
|
|
async def sub_pitcher_command(
|
|
self, interaction: discord.Interaction, new_player: int,
|
|
batting_order: Literal['this-spot', '1', '2', '3', '4', '5', '6', '7', '8', '9'] = None):
|
|
this_game, owner_team, this_play = await self.checks_log_interaction(interaction)
|
|
if False in (this_game, owner_team, this_play):
|
|
return
|
|
|
|
this_card = await db_get(f'cards', object_id=int(new_player))
|
|
if this_card["team"]["id"] != owner_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
|
|
new_post = False
|
|
|
|
# Check for simple position change
|
|
in_lineup = get_one_lineup(this_game.id, team_id=owner_team['id'], active=True, card_id=card_id)
|
|
if in_lineup is not None:
|
|
new_pitcher = patch_lineup(in_lineup.id, position='P')
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
q_text = f'It looks like you are forfeiting the DH by moving {player_desc(this_card["player"])} to ' \
|
|
f'the mound. __You will not be able to undo this sub even with the undo-play command__ so real ' \
|
|
f'quick: are you sure?'
|
|
question = await interaction.channel.send(q_text, view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.edit(content=f'~~{q_text}~~\nFuck the DH \U0000270A', view=None)
|
|
else:
|
|
await question.delete()
|
|
await interaction.edit_original_response(content=f'~~{q_text}~~\nI will hold off for now.')
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game)
|
|
)
|
|
return
|
|
|
|
old_pitcher = get_pitcher(this_game, this_play)
|
|
patch_lineup(old_pitcher.id, active=False)
|
|
patch_play(this_play.id, pitcher_id=new_pitcher.id)
|
|
this_play.pitcher = new_pitcher
|
|
else:
|
|
if this_play is None:
|
|
after_play = 0
|
|
|
|
old_pit_order = 10
|
|
if batting_order is None:
|
|
batting_order = 10
|
|
else:
|
|
batting_order = int(batting_order)
|
|
|
|
else:
|
|
if this_play.pitcher.team_id != owner_team['id']:
|
|
await interaction.edit_original_response(
|
|
content='It looks like your team is batting right now - '
|
|
'please make this sub once you take the field.')
|
|
return
|
|
|
|
old_pit_order = this_play.pitcher.batting_order
|
|
if batting_order is None:
|
|
batting_order = old_pit_order
|
|
else:
|
|
batting_order = int(batting_order)
|
|
|
|
after_play = this_play.play_num - 1
|
|
|
|
this_lineup = {
|
|
'game_id': this_game.id,
|
|
'team_id': owner_team['id'],
|
|
'player_id': player_id,
|
|
'card_id': card_id,
|
|
'position': 'P',
|
|
'batting_order': batting_order,
|
|
'after_play': after_play
|
|
}
|
|
|
|
make_sub(this_lineup)
|
|
if old_pit_order != batting_order:
|
|
patch_lineup(this_play.pitcher.id, active=False)
|
|
|
|
if new_post:
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game)
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
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)
|
|
if this_play is not None:
|
|
# 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['id'] == home_team['id'] 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["p_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, as_string=False
|
|
)
|
|
make_sub(await ai_manager.get_relief_pitcher(this_play, ai_team, this_game.game_type))
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@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)
|
|
def_team = await db_get('teams', object_id=this_play.pitcher.team_id)
|
|
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)}*'
|
|
|
|
logging.debug(f'calling of embed')
|
|
await show_outfield_cards(interaction, this_play)
|
|
logging.debug(f'done with of embed')
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Is {lead_runner["p_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["p_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["p_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["p_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["p_name"]} thrown out {at_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)
|
|
|
|
if single_type == 'uncapped':
|
|
await interaction.edit_original_response(content=f'Uncapped single has been logged')
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
|
|
@group_log.command(name='frame-pitch', description=f'Walk/strikeout split; determined by home plate umpire')
|
|
async def log_frame_check(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)
|
|
|
|
frame_result = dice.frame_plate_check(owner_team, this_game.id)
|
|
logging.info(f'Frame Result:\n{frame_result}')
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=frame_result['embed']
|
|
)
|
|
|
|
if frame_result['is_walk']:
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
patch_play(this_play.id, pa=1, walk=1)
|
|
batter_to_base = 1
|
|
else:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1, so=1)
|
|
advance_runners(this_play.id, 0)
|
|
batter_to_base = None
|
|
|
|
complete_play(this_play.id, batter_to_base=batter_to_base)
|
|
|
|
await interaction.channel.send(
|
|
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)}*'
|
|
|
|
logging.debug(f'calling of embed')
|
|
await show_outfield_cards(interaction, this_play)
|
|
logging.debug(f'done with of embed')
|
|
|
|
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["p_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["p_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["p_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["p_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:
|
|
batter_to_base = 3
|
|
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["p_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)
|
|
|
|
if double_type == 'uncapped':
|
|
await interaction.edit_original_response(content=f'Uncapped double has been logged')
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
else:
|
|
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)
|
|
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["p_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["p_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["p_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 == 4 and this_play.on_third:
|
|
patch_play(
|
|
this_play.id, sb=1, on_third_final=4, runner_id=this_play.on_third.id, catcher_id=catcher.id
|
|
)
|
|
if this_play.on_second:
|
|
advance_one_runner(this_play.id, 2, 1)
|
|
if this_play.on_first:
|
|
advance_one_runner(this_play.id, 1, 1)
|
|
elif to_base == 3 and this_play.on_second:
|
|
if not this_play.on_third:
|
|
advance_runners(this_play.id, 1, is_error=True)
|
|
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["p_name"]} is blocked by the runner at third.'
|
|
)
|
|
patch_play(this_play.id, locked=False)
|
|
return
|
|
if this_play.on_first:
|
|
advance_one_runner(
|
|
this_play.id, from_base=1, num_bases=1
|
|
)
|
|
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["p_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 == 4 and this_play.on_third:
|
|
patch_play(
|
|
this_play.id, sb=1, on_third_final=4, runner_id=this_play.on_third.id, catcher_id=catcher.id
|
|
)
|
|
if this_play.on_second:
|
|
advance_one_runner(this_play.id, 2, 2)
|
|
if this_play.on_first:
|
|
advance_one_runner(this_play.id, 1, 2)
|
|
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["p_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["p_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 == 4 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
|
|
)
|
|
if this_play.on_second:
|
|
advance_one_runner(this_play.id, 2, 1)
|
|
if this_play.on_first:
|
|
advance_one_runner(this_play.id, 1, 1)
|
|
elif to_base == 3 and this_play.on_second:
|
|
if not this_play.on_third:
|
|
advance_runners(this_play.id, 1)
|
|
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["p_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["p_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["p_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)
|
|
except AttributeError as e:
|
|
logging.error(f'Could not undo second play in game {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}')
|
|
undo_subs(this_game, latest_play.play_num)
|
|
|
|
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 = await 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["p_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
|
|
|
|
view = Confirm([interaction.user], label_type='yes')
|
|
question = await interaction.channel.send(f'Did {defender["p_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["p_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["p_name"]} give up an error or rare play?', view=view)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.delete()
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['1 base', '2 bases', '3 bases', 'Rare Play', None]
|
|
)
|
|
question = await interaction.channel.send(f'What kind of error did {defender["p_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 this_play.on_base_code == 0:
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 0)
|
|
complete_play(this_play.id)
|
|
else:
|
|
if position.value not in ['LF', 'CF', 'RF']:
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['G1', 'G2', 'G3', 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)
|
|
logging.info(f'obc: {this_play.on_base_code}')
|
|
await view.wait()
|
|
|
|
logging.info(f'gameplay - view: {view} / view.value: {view.value}')
|
|
gb_type = view.value
|
|
logging.info(f'gameplay - gb_type: {gb_type}')
|
|
if not view.value:
|
|
await question.edit('Okay, we can try this again later.')
|
|
|
|
else:
|
|
await question.delete()
|
|
|
|
playing_in = False
|
|
batter_to_base = None
|
|
if runner_on_third(this_play) and gb_type not in ['FO', 'PO']:
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type='yes')
|
|
question = await interaction.channel.send(
|
|
f'Was the defender playing in?', view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
playing_in = True
|
|
else:
|
|
playing_in = False
|
|
|
|
await question.delete()
|
|
logging.info(f'bot playing_in: {playing_in} / view.value: {view.value} / gb_type: {gb_type}')
|
|
|
|
if gb_type == 'G1':
|
|
if (not playing_in and this_play.on_base_code == 0) or \
|
|
(playing_in and (this_play.on_base_code in [3, 6])):
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
elif playing_in and this_play.on_base_code == 5:
|
|
batter_to_base = gb_result_7(this_play)
|
|
|
|
elif (not playing_in and this_play.on_base_code in [1, 5, 7]) or \
|
|
(playing_in and (this_play.on_base_code in [1, 4])):
|
|
batter_to_base = gb_result_2(this_play)
|
|
|
|
elif not playing_in and this_play.on_base_code in [3, 6]:
|
|
batter_to_base = gb_result_3(this_play)
|
|
|
|
elif this_play.on_base_code == 2:
|
|
if position.value == '3B':
|
|
this_def = '3b'
|
|
elif position.value in ['1B', '2B']:
|
|
this_def = '1b-2b'
|
|
else:
|
|
this_def = 'ss-p-c'
|
|
batter_to_base = await gb_result_12(this_play, this_def, interaction)
|
|
|
|
elif playing_in and this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_10(this_play)
|
|
|
|
elif not playing_in and this_play.on_base_code == 4:
|
|
if position.value in ['C', '3B']:
|
|
this_def = 'c-3b'
|
|
else:
|
|
this_def = 'else'
|
|
batter_to_base = gb_result_13(this_play, this_def)
|
|
|
|
elif gb_type == 'G2':
|
|
if (not playing_in and this_play.on_base_code == 0) or \
|
|
(playing_in and this_play.on_base_code in [3, 6]):
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
elif playing_in and this_play.on_base_code == 5:
|
|
batter_to_base = gb_result_7(this_play)
|
|
|
|
elif (not playing_in and this_play.on_base_code in [1, 4, 5, 7]) or \
|
|
(playing_in and (this_play.on_base_code in [1, 4])):
|
|
batter_to_base = gb_result_4(this_play)
|
|
|
|
elif not playing_in and this_play.on_base_code in [3, 6]:
|
|
if position.value in ['SS', '2B']:
|
|
to_mif = True
|
|
else:
|
|
to_mif = False
|
|
batter_to_base = gb_result_5(this_play, to_mif)
|
|
|
|
elif playing_in and this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_11(this_play)
|
|
|
|
elif this_play.on_base_code == 2:
|
|
if position.value == '3B':
|
|
this_def = '3b'
|
|
elif position.value in ['1B', '2B']:
|
|
this_def = '1b-2b'
|
|
else:
|
|
this_def = 'ss-p-c'
|
|
batter_to_base = await gb_result_12(this_play, this_def, interaction)
|
|
|
|
elif gb_type == 'G3':
|
|
if not playing_in and this_play.on_base_code == 0:
|
|
batter_to_base = gb_result_1(this_play)
|
|
|
|
elif playing_in and this_play.on_base_code == 5:
|
|
batter_to_base = gb_result_7(this_play)
|
|
|
|
elif playing_in and this_play.on_base_code == 7:
|
|
batter_to_base = gb_result_11(this_play)
|
|
|
|
elif not playing_in and this_play.on_base_code == 2:
|
|
if position.value == '3B':
|
|
this_def = '3b'
|
|
elif position.value in ['1B', '2B']:
|
|
this_def = '1b-2b'
|
|
else:
|
|
this_def = 'ss-p-c'
|
|
batter_to_base = await gb_result_12(this_play, this_def, interaction)
|
|
|
|
elif playing_in and this_play.on_base_code in [3, 6]:
|
|
batter_to_base = await gb_decide(
|
|
this_play, interaction, await get_player(this_play.game, this_play.on_third), 3
|
|
)
|
|
|
|
else:
|
|
batter_to_base = gb_result_3(this_play)
|
|
|
|
else:
|
|
logging.info(f'no match; log out')
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 0)
|
|
|
|
complete_play(this_play.id, batter_to_base)
|
|
|
|
else:
|
|
view = ButtonOptions(responders=[interaction.user], labels=['F1', 'F2', 'F3', 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 == 'Rare Play':
|
|
patch_play(this_play.id, outs=1)
|
|
batter_to_base = None
|
|
elif 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 == 'Rare Play':
|
|
patch_play(this_play.id, outs=1)
|
|
batter_to_base = None
|
|
elif 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)
|
|
elif error_allowed == 'Rare Play':
|
|
if position.value not in ['LF', 'CF', 'RF']:
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['G1', 'G2', 'G3', 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)
|
|
logging.info(f'obc: {this_play.on_base_code}')
|
|
await view.wait()
|
|
|
|
logging.info(f'gameplay - view: {view} / view.value: {view.value}')
|
|
gb_type = view.value
|
|
logging.info(f'gameplay - gb_type: {gb_type}')
|
|
if not view.value:
|
|
await question.edit('Okay, we can try this again later.')
|
|
else:
|
|
await question.delete()
|
|
if gb_type == 'G1':
|
|
if runner_on_first(this_play):
|
|
await self.groundballs(interaction, this_game, this_play, 'b')
|
|
else:
|
|
await self.groundballs(interaction, this_game, this_play, 'a')
|
|
elif gb_type == 'G2':
|
|
if this_play.on_base_code != 0:
|
|
await self.groundballs(interaction, this_game, this_play, 'c')
|
|
else:
|
|
await self.groundballs(interaction, this_game, this_play, 'b')
|
|
elif gb_type == 'G3':
|
|
if this_play.on_base_code != 0:
|
|
await single_onestar(this_play)
|
|
else:
|
|
await self.groundballs(interaction, this_game, this_play, 'c')
|
|
else:
|
|
view = ButtonOptions(responders=[interaction.user], labels=['F1', 'F2', 'F3', 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 == 'F1':
|
|
fly_code = 'a'
|
|
elif view.value == 'F2':
|
|
fly_code = 'b'
|
|
else:
|
|
fly_code = 'c'
|
|
|
|
if this_play.starting_outs == 2 or this_play.on_base_code == 0:
|
|
await self.flyballs(interaction, this_game, this_play, fly_code)
|
|
else:
|
|
if fly_code == 'a':
|
|
patch_play(this_play.id, pa=1, ab=1, outs=1)
|
|
advance_runners(this_play.id, 2)
|
|
if this_play.on_third or this_play.on_second:
|
|
patch_play(this_play.id, ab=0)
|
|
elif fly_code == 'b':
|
|
if runner_on_third(this_play):
|
|
patch_play(this_play.id, pa=1, ab=1, outs=2, on_third_final=False)
|
|
else:
|
|
await self.flyballs(interaction, this_game, this_play, fly_code, comp_play=False)
|
|
elif fly_code == 'c':
|
|
patch_play(this_play.id, pa=1, ab=1, outs=2)
|
|
if runner_on_third(this_play):
|
|
patch_play(this_play.id, on_third_final=False)
|
|
elif runner_on_second(this_play):
|
|
patch_play(this_play.id, on_second_final=False)
|
|
else:
|
|
patch_play(this_play.id, on_first_final=False)
|
|
|
|
complete_play(this_play.id)
|
|
|
|
else:
|
|
if position.value == 'C':
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=['G1/G2/G3/SPD', 'FO', '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.edit(
|
|
content=f'Hmm...you keep thinking on it and get back to me when you\'re ready.',
|
|
view=None
|
|
)
|
|
return
|
|
elif view.value == 'FO':
|
|
await question.edit(content=f'**The ball dropped foul; batter swings again.**', view=None)
|
|
patch_play(this_play.id, defender_id=False, check_pos='false')
|
|
await interaction.channel.send(
|
|
content=None, embed=await self.get_game_state_embed(this_game, full_length=False)
|
|
)
|
|
return
|
|
else:
|
|
await question.delete()
|
|
|
|
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)
|
|
)
|
|
)
|
|
|
|
def_team_id = this_game.away_team_id if this_play.inning_half == 'Bot' else this_game.home_team_id
|
|
def_team = await db_get('teams', object_id=def_team_id)
|
|
embed = get_team_embed(f'{def_team["sname"]} {position}', def_team)
|
|
embed.description = f'{defender["p_name"]}'
|
|
embed.set_image(url=defender['image'])
|
|
if this_game.is_pd:
|
|
embed.set_footer(text=f'Paper Dynasty 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'Paper Dynasty 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))
|