Run Black formatter across 83 files and fix 1514 ruff violations: - E722: bare except → typed exceptions (17 fixes) - E711/E712/E721: comparison style fixes with noqa for SQLAlchemy (44 fixes) - F841: unused variable assignments (70 fixes) - F541/F401: f-string and import cleanup (1383 auto-fixes) Remaining 925 errors are all F403/F405 (star imports) — structural, requires converting to explicit imports in a separate effort. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5714 lines
234 KiB
Python
5714 lines
234 KiB
Python
import asyncio
|
|
import logging
|
|
import discord
|
|
import math
|
|
import os
|
|
|
|
from in_game import ai_manager
|
|
|
|
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 Literal, Optional
|
|
|
|
from dice import sa_fielding_roll_legacy
|
|
from helpers import (
|
|
SBA_PLAYERS_ROLE_NAME,
|
|
PD_PLAYERS_ROLE_NAME,
|
|
random_conf_gif,
|
|
PD_SEASON,
|
|
IMAGES,
|
|
get_pos_abbrev,
|
|
SBA_COLOR,
|
|
get_roster_lineups,
|
|
give_packs,
|
|
send_to_channel,
|
|
get_channel,
|
|
team_role,
|
|
get_cal_user,
|
|
ButtonOptions,
|
|
get_ratings_guide,
|
|
get_team_by_owner,
|
|
player_desc,
|
|
player_pcard,
|
|
player_bcard,
|
|
get_team_embed,
|
|
Confirm,
|
|
get_sheets,
|
|
Dropdown,
|
|
SELECT_CARDSET_OPTIONS,
|
|
DropdownView,
|
|
)
|
|
from in_game.ai_manager import check_pitching_sub
|
|
from in_game.game_helpers import (
|
|
single_onestar,
|
|
single_wellhit,
|
|
double_twostar,
|
|
double_threestar,
|
|
triple,
|
|
runner_on_first,
|
|
runner_on_second,
|
|
runner_on_third,
|
|
gb_result_1,
|
|
gb_result_2,
|
|
gb_result_3,
|
|
gb_result_4,
|
|
gb_result_5,
|
|
gb_result_6,
|
|
gb_result_7,
|
|
gb_result_8,
|
|
gb_result_9,
|
|
gb_result_10,
|
|
gb_result_11,
|
|
gb_result_12,
|
|
gb_result_13,
|
|
gb_decide,
|
|
show_outfield_cards,
|
|
legal_check,
|
|
get_pitcher,
|
|
)
|
|
from api_calls import db_get, db_patch, db_post, db_delete, get_team_by_abbrev
|
|
from db_calls_gameplay import (
|
|
StratGame,
|
|
StratPlay,
|
|
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_pitching_decisions,
|
|
get_or_create_bullpen,
|
|
get_active_games,
|
|
patch_lineup,
|
|
get_plays,
|
|
get_manager,
|
|
get_one_game,
|
|
load_ai,
|
|
ai_batting,
|
|
undo_subs,
|
|
get_dbready_plays,
|
|
)
|
|
|
|
logger = logging.getLogger("discord_app")
|
|
|
|
|
|
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"
|
|
elif "exhibition" in x.game_type:
|
|
gt_string = "Exhibition"
|
|
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:
|
|
logger.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:
|
|
logger.error("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:
|
|
logger.error("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:
|
|
logger.error("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:
|
|
logger.error("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("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)
|
|
logger.info(f"away_lineup: {away_lineup}")
|
|
logger.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,
|
|
}
|
|
logger.error(
|
|
f"One ore more lineups not submitted in Game {game.id}\n\ngame_state: {game_state}"
|
|
)
|
|
return game_state
|
|
else:
|
|
logger.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"
|
|
)
|
|
logger.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:
|
|
logger.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 = "Please sub in a pitcher to continue"
|
|
else:
|
|
error_message = "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
|
|
logger.debug(f"game_state: {game_state}")
|
|
|
|
return game_state
|
|
|
|
async def initialize_play_plus_embed(
|
|
self, game: StratGame, full_length=True, for_liveboard=False
|
|
):
|
|
game_state = await self.get_game_state(game)
|
|
|
|
logger.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"
|
|
elif "exhibition" in game.game_type:
|
|
gt_string = " - Exhibition"
|
|
|
|
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
|
|
|
|
logger.debug("no errors")
|
|
pitching_sub = None
|
|
ai_note = ""
|
|
gm_name = ""
|
|
fatigue = await ai_manager.is_pitcher_fatigued(game_state["curr_play"])
|
|
logger.debug("do AI stuff")
|
|
# If an AI team is playing
|
|
if True in [
|
|
game_state["pitcher"]["team"]["is_ai"],
|
|
game_state["batter"]["team"]["is_ai"],
|
|
]:
|
|
logger.debug("Checking AI stuff")
|
|
|
|
# AI Team is pitching
|
|
if game_state["pitcher"]["team"]["is_ai"]:
|
|
if fatigue:
|
|
pitching_sub = await check_pitching_sub(
|
|
game_state["curr_play"], game_state["pitcher"]["team"]
|
|
)
|
|
if pitching_sub is not None:
|
|
game_state = await self.get_game_state(game)
|
|
|
|
ai_data = await ai_manager.pitching_ai_note(
|
|
game_state["curr_play"], game_state["pitcher"]
|
|
)
|
|
logger.debug(f"ai_data: {ai_data}")
|
|
ai_note = ai_data["note"]
|
|
gm_name = ai_data["gm_name"]
|
|
|
|
# AI Team is batting
|
|
if 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 (
|
|
pitching_sub is not None
|
|
or (fatigue and pitching_sub is None)
|
|
or abs(
|
|
game_state["curr_play"].home_score - game_state["curr_play"].away_score
|
|
)
|
|
>= 10
|
|
):
|
|
color = discord.Colour.red()
|
|
else:
|
|
color = int(SBA_COLOR, 16)
|
|
|
|
embed = discord.Embed(
|
|
title=f'{game_state["away_team"]["sname"]} @ {game_state["home_team"]["sname"]}{gt_string}',
|
|
color=color,
|
|
)
|
|
logger.info("got embed")
|
|
|
|
footer_text = f"Paper Dynasty Season {PD_SEASON}"
|
|
if game.short_game:
|
|
footer_text += " - Reminder: all pitchers have POW(1) in 3-inning games"
|
|
embed.set_footer(text=footer_text, icon_url=IMAGES["logo"])
|
|
|
|
embed.add_field(name="Game State", value=game_state["scorebug"], inline=False)
|
|
embed.set_thumbnail(url=player_pcard(game_state["pitcher"]))
|
|
|
|
logger.info("check mercy")
|
|
if (
|
|
abs(game_state["curr_play"].home_score - game_state["curr_play"].away_score)
|
|
>= 10
|
|
):
|
|
embed.description = "***Mercy rule in effect***"
|
|
|
|
logger.info("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}'
|
|
)
|
|
|
|
logger.info("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}'
|
|
)
|
|
|
|
logger.info("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 fatigue and pitching_sub is None:
|
|
pitcher_string += "\n***F A T I G U E D***"
|
|
|
|
logger.info("set embed pitcher/batter")
|
|
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"]))
|
|
|
|
logger.info("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"
|
|
|
|
logger.info("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)
|
|
|
|
if len(ai_note) > 0:
|
|
embed.add_field(name=f"{gm_name} will...", value=ai_note, inline=False)
|
|
|
|
if pitching_sub is not None:
|
|
embed.add_field(
|
|
name="SUBSTITUTION",
|
|
value=f'The {game_state["pitcher"]["team"]["sname"]} have brought in '
|
|
f"**{player_desc(pitching_sub)}** to pitch",
|
|
)
|
|
|
|
logger.info(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(
|
|
"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(
|
|
"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="Hmm...not sure what else this could be. If you expected a different "
|
|
"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()
|
|
|
|
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()
|
|
|
|
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="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
|
|
|
|
logger.debug("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(
|
|
"Was the defender playing in?", view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
playing_in = True
|
|
else:
|
|
playing_in = False
|
|
|
|
await question.delete()
|
|
logger.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(
|
|
"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(
|
|
"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(
|
|
"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(
|
|
"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:
|
|
logger.debug("calling of embed")
|
|
await show_outfield_cards(interaction, this_play)
|
|
logger.debug("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:
|
|
logger.debug("calling of embed")
|
|
await show_outfield_cards(interaction, this_play)
|
|
logger.debug("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="Ope. There is already a game going on in this channel. Please wait for it to complete "
|
|
"before starting a new one."
|
|
)
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != "Public Fields":
|
|
await interaction.response.send_message(
|
|
"Why don't you head down to one of the Public Fields that way other humans can help if anything "
|
|
"pops up?"
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logger.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"]
|
|
# logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: {is_ranked}')
|
|
logger.debug(f"away: {away_team} / home: {home_team} / week: {week_num}")
|
|
|
|
if not away_team["is_ai"] and not home_team["is_ai"]:
|
|
logger.error(
|
|
f'MLB Campaign game between {away_team["abbrev"]} and {home_team["abbrev"]} has no AI'
|
|
)
|
|
await interaction.edit_original_response(
|
|
content="I don't see an AI team in this MLB Campaign game. Run `/new-game mlb-campaign` again with "
|
|
"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="Ope. Looks like you haven't completed the Minor League campaign, yet!\n\n"
|
|
"To play **Flashback** games, you need to defeat all 30 MLB teams in the Minor League "
|
|
"campaign. You can see your progress with `/record`.\n\n"
|
|
"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="Ope. Looks like you haven't received the **PD - Major League** role, yet!\n\n"
|
|
"To play **Major League** games, you need to defeat all 30 MLB teams in the Minor League "
|
|
"campaign. You can see your progress with `/record`.\n\n"
|
|
"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="Ope. Looks like you haven't received the **PD - Hall of Fame** role, yet!\n\n"
|
|
"To play **Hall of Fame** games, you need to defeat all 30 MLB teams in the Minor League "
|
|
"and Major League campaign. You can see your progress with `/record`.\n\n"
|
|
"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,
|
|
}
|
|
)
|
|
logger.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("cards", object_id=sp_card_id)
|
|
|
|
if human_sp_card["team"]["id"] != human_team["id"]:
|
|
logger.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="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("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)
|
|
logger.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"]}...'
|
|
)
|
|
|
|
logger.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)
|
|
logger.info(f'new-game - got lineup for {ai_team["abbrev"]}')
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logger.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
|
|
|
|
logger.debug(f'Setting lineup for {ai_team["sname"]} in PD game')
|
|
logger.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.initialize_play_plus_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="Ope. There is already a game going on in this channel. Please wait for it to complete "
|
|
"before starting a new one."
|
|
)
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != "Public Fields":
|
|
await interaction.response.send_message(
|
|
"Why don't you head down to one of the Public Fields that way other humans can help if anything "
|
|
"pops up?"
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logger.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"]:
|
|
logger.error(
|
|
f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI'
|
|
)
|
|
await interaction.edit_original_response(
|
|
content="Only human vs human games can be ranked - run `/new-game` again and double-check the "
|
|
"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"]
|
|
logger.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",
|
|
}
|
|
)
|
|
logger.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.initialize_play_plus_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="Ope. There is already a game going on in this channel. Please wait for it to complete "
|
|
"before starting a new one."
|
|
)
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != "Public Fields":
|
|
await interaction.response.send_message(
|
|
"Why don't you head down to one of the Public Fields that way other humans can help if anything "
|
|
"pops up?"
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logger.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"]:
|
|
logger.error(
|
|
f'Ranked game between {away_team["abbrev"]} and {home_team["abbrev"]} has an AI'
|
|
)
|
|
await interaction.edit_original_response(
|
|
content="This command is for human v human games - run `/new-game` again and double-check the "
|
|
"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"]
|
|
logger.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",
|
|
}
|
|
)
|
|
logger.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.initialize_play_plus_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["2024 Season", "Super Ultra Championship"],
|
|
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="Ope. There is already a game going on in this channel. Please wait for it to complete "
|
|
"before starting a new one."
|
|
)
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != "Public Fields":
|
|
await interaction.response.send_message(
|
|
"Why don't you head down to one of the Public Fields that way other humans can help if anything "
|
|
"pops up?"
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logger.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]
|
|
|
|
if interaction.user.id == 258104532423147520:
|
|
main_team = await get_team_by_abbrev("SKB")
|
|
else:
|
|
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="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="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
|
|
else:
|
|
logger.info(f"opponent: {opponent}")
|
|
|
|
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,
|
|
}
|
|
)
|
|
logger.info(
|
|
f'Game {this_game.id} between {team["abbrev"]} and {opponent["abbrev"]} is posted!'
|
|
)
|
|
await team_role(interaction, main_team)
|
|
|
|
all_lineups = []
|
|
# Get Human SP
|
|
human_sp_card = await db_get("cards", object_id=sp_card_id)
|
|
|
|
if human_sp_card["team"]["id"] != team["id"]:
|
|
logger.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
|
|
|
|
logger.info(
|
|
f'Appending Human SP ({human_sp_card["player"]["p_name"]}) to all_lineups'
|
|
)
|
|
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:
|
|
logger.info(f'Getting SP for {opponent["abbrev"]}')
|
|
await interaction.edit_original_response(
|
|
content="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("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)
|
|
logger.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"]}...'
|
|
)
|
|
|
|
logger.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)
|
|
logger.info(f'new-game-gauntlet - got lineup for {opponent["abbrev"]}')
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logger.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
|
|
|
|
logger.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.initialize_play_plus_embed(this_game, full_length=False),
|
|
)
|
|
return
|
|
|
|
@group_new_game.command(
|
|
name="exhibition", description="Start a new custom game against an AI"
|
|
)
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def new_game_exhibition_command(
|
|
self,
|
|
interaction: discord.Interaction,
|
|
away_team_abbrev: str,
|
|
home_team_abbrev: str,
|
|
sp_card_id: int,
|
|
num_innings: Literal[9, 3] = 9,
|
|
cardsets: Literal[
|
|
"Minor League", "Major League", "Hall of Fame", "Flashback", "Custom"
|
|
] = "Custom",
|
|
):
|
|
await interaction.response.defer()
|
|
|
|
conflict = get_one_game(channel_id=interaction.channel.id, active=True)
|
|
if conflict:
|
|
await interaction.edit_original_response(
|
|
content="Ope. There is already a game going on in this channel. Please wait for it to complete "
|
|
"before starting a new one."
|
|
)
|
|
return
|
|
|
|
try:
|
|
if interaction.channel.category.name != "Public Fields":
|
|
await interaction.response.send_message(
|
|
"Why don't you head down to one of the Public Fields that way other humans can help if anything "
|
|
"pops up?"
|
|
)
|
|
return
|
|
except Exception as e:
|
|
logger.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
|
|
|
|
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"]
|
|
# logger.debug(f'away: {away_team} / home: {home_team} / week: {week_num} / ranked: {is_ranked}')
|
|
logger.debug(f"away: {away_team} / home: {home_team} / week: {week_num}")
|
|
|
|
if not away_team["is_ai"] and not home_team["is_ai"]:
|
|
logger.error(
|
|
f'Exhibition game between {away_team["abbrev"]} and {home_team["abbrev"]} has no AI'
|
|
)
|
|
await interaction.edit_original_response(
|
|
content="I don't see an AI team in this Exhibition game. Run `/new-game mlb-campaign` again with "
|
|
"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
|
|
|
|
league_name = "exhibition"
|
|
|
|
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,
|
|
}
|
|
)
|
|
logger.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("cards", object_id=sp_card_id)
|
|
|
|
if human_sp_card["team"]["id"] != human_team["id"]:
|
|
logger.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_sp_card["player"]["p_name"]} and belongs to '
|
|
f'{human_sp_card["team"]["sname"]}. Will you double check that before we get started?'
|
|
)
|
|
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,
|
|
}
|
|
)
|
|
|
|
async def get_ai_sp_roster(
|
|
interaction, this_game, ai_team, home_team, league_name, all_lineups
|
|
):
|
|
# Get AI Starting Pitcher
|
|
try:
|
|
await interaction.channel.send(
|
|
content="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 = 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("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)
|
|
logger.error(f'could not start an AI game with {ai_team["sname"]}: {e}')
|
|
await interaction.channel.send(
|
|
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?"
|
|
)
|
|
raise KeyError(
|
|
f'A Starting Pitcher could not be found for the {ai_team["lname"]}.'
|
|
)
|
|
|
|
# Get AI Lineup
|
|
try:
|
|
await interaction.channel.send(
|
|
content=f'I am getting a lineup card from the {ai_team["sname"]}...'
|
|
)
|
|
|
|
logger.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)
|
|
logger.info(f'new-game - got lineup for {ai_team["abbrev"]}')
|
|
|
|
except Exception as e:
|
|
patch_game(this_game.id, active=False)
|
|
logger.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
|
|
|
|
logger.debug(f'Setting lineup for {ai_team["sname"]} in PD game')
|
|
logger.debug(f"lineups: {all_lineups}")
|
|
post_lineups(all_lineups)
|
|
|
|
if cardsets in ["Minor League", "Major League", "Hall of Fame", "Flashback"]:
|
|
if cardsets == "Minor League":
|
|
cardset_ids = "17,8"
|
|
backup_cardset_ids = "13"
|
|
elif cardsets == "Major League":
|
|
cardset_ids = "17,18,13,11,7,8"
|
|
backup_cardset_ids = "9,3"
|
|
elif cardsets == "Hall of Fame":
|
|
all_c = [str(x) for x in range(1, 20)]
|
|
cardset_ids = f'{",".join(all_c)}'
|
|
backup_cardset_ids = None
|
|
else:
|
|
# Flashback cardsets
|
|
cardset_ids = "11,7,6,12"
|
|
backup_cardset_ids = "13,5"
|
|
this_game = patch_game(
|
|
this_game.id,
|
|
cardset_ids=cardset_ids,
|
|
backup_cardset_ids=backup_cardset_ids,
|
|
)
|
|
|
|
await get_ai_sp_roster(
|
|
interaction, this_game, ai_team, home_team, league_name, 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.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
else:
|
|
|
|
async def my_callback(interaction: discord.Interaction, values):
|
|
cardset_ids = ",".join(values)
|
|
patch_game(this_game.id, cardset_ids=cardset_ids)
|
|
# await interaction.response.send_message(
|
|
# f'Your selection{"s are" if len(values) > 1 else " is"}: {", ".join(values)}')
|
|
|
|
await get_ai_sp_roster(
|
|
interaction, this_game, ai_team, home_team, league_name, 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.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
|
|
my_dropdown = Dropdown(
|
|
option_list=SELECT_CARDSET_OPTIONS,
|
|
placeholder="Select up to 8 cardsets to include",
|
|
callback=my_callback,
|
|
max_values=len(SELECT_CARDSET_OPTIONS),
|
|
)
|
|
view = DropdownView([my_dropdown])
|
|
await interaction.edit_original_response(content=None, view=view)
|
|
|
|
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.initialize_play_plus_embed(this_game)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"could not post game state embed: {e}")
|
|
question = await ctx.send(
|
|
"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("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, this_game.id)
|
|
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
|
|
logger.info(f"Ending Game {this_game.id}")
|
|
|
|
response = await interaction.edit_original_response(
|
|
content="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 (
|
|
owner_team["id"] not 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
|
|
logger.debug(f"latest play: {latest_play}")
|
|
if not this_game.short_game:
|
|
if latest_play.starting_outs == 0:
|
|
logger.debug("no outs")
|
|
if latest_play.inning_half.lower() == "top":
|
|
logger.debug("top of inning")
|
|
if (
|
|
latest_play.inning_num > 9
|
|
and latest_play.away_score != latest_play.home_score
|
|
):
|
|
logger.debug("after the ninth and not tied")
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logger.debug("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:
|
|
logger.debug("bottom half and home team winning")
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logger.debug("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"
|
|
):
|
|
logger.info("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:
|
|
logger.debug("no outs")
|
|
if latest_play.inning_half.lower() == "top":
|
|
logger.debug("top of inning")
|
|
if (
|
|
latest_play.inning_num > 3
|
|
and latest_play.away_score != latest_play.home_score
|
|
):
|
|
logger.debug("after the ninth and not tied")
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logger.debug("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:
|
|
logger.debug("bottom half and home team winning")
|
|
valid_end = True
|
|
if abs(latest_play.home_score - latest_play.away_score) >= 10:
|
|
logger.debug("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"
|
|
):
|
|
logger.info("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:
|
|
logger.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:
|
|
logger.error(f"end-game - Could not post decisions: {e}")
|
|
failure = True
|
|
|
|
if failure:
|
|
try:
|
|
await db_delete("decisions/game", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete decisions")
|
|
|
|
try:
|
|
await db_delete("plays/game", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete plays")
|
|
|
|
try:
|
|
await db_delete("games", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete game")
|
|
|
|
await interaction.channel.send(
|
|
content="That did not go well and I wasn't able to submit this game. I recommend pinging Cal so he "
|
|
"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.initialize_play_plus_embed(this_game, full_length=False),
|
|
)
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type="yes")
|
|
question = await interaction.edit_original_response(
|
|
content="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:
|
|
logger.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:
|
|
logger.error(f"end-game - Could not post decisions: {e}")
|
|
failure = True
|
|
|
|
if failure:
|
|
try:
|
|
await db_delete("decisions/game", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete decisions")
|
|
|
|
try:
|
|
await db_delete("plays/game", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete plays")
|
|
|
|
try:
|
|
await db_delete("games", object_id=final_game["id"])
|
|
except Exception:
|
|
logger.error("could not delete game")
|
|
|
|
await interaction.channel.send(
|
|
content="That did not go well and I wasn't able to submit this game. I recommend pinging Cal so he "
|
|
"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
|
|
logger.debug("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,
|
|
)
|
|
|
|
logger.debug("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"]}')
|
|
|
|
logger.debug("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"}'
|
|
)
|
|
logger.debug("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,
|
|
)
|
|
|
|
logger.debug("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)
|
|
|
|
logger.info(f"potg: {potg_string}")
|
|
logger.debug("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="Pitching",
|
|
value=pit_string,
|
|
)
|
|
|
|
def name_list(raw_list: list) -> str:
|
|
logger.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 = ""
|
|
logger.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
|
|
|
|
logger.info("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="Baserunning", value=run_string)
|
|
|
|
logger.info("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."
|
|
|
|
logger.info("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,
|
|
)
|
|
logger.info("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,
|
|
responders=[interaction.user],
|
|
)
|
|
|
|
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)
|
|
|
|
logger.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']
|
|
# }
|
|
#
|
|
# logger.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:
|
|
# # logger.info(f'line: {line}')
|
|
# this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
|
|
# # logger.info(f'away / this_stats: {this_stats}')
|
|
# away_stats['p_lines'].extend(this_stats)
|
|
# if 'score' not in home_stats:
|
|
# # logger.info(f'score not in home_stats')
|
|
# home_stats['score'] = this_stats[0]['pl_runs']
|
|
# else:
|
|
# # logger.info(f'score is in home_stats')
|
|
# home_stats['score'] += this_stats[0]['pl_runs']
|
|
# if 'hits' not in home_stats:
|
|
# # logger.info(f'hits not in home_stats')
|
|
# home_stats['hits'] = this_stats[0]['pl_hit']
|
|
# else:
|
|
# # logger.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)
|
|
# logger.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:
|
|
# # logger.info(f'line: {line}')
|
|
# this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
|
|
# # logger.info(f'home / this_stats: {this_stats}')
|
|
# home_stats['p_lines'].extend(this_stats)
|
|
# if 'score' not in away_stats:
|
|
# # logger.info(f'score not in away_stats')
|
|
# away_stats['score'] = this_stats[0]['pl_runs']
|
|
# else:
|
|
# # logger.info(f'score is in away_stats')
|
|
# away_stats['score'] += this_stats[0]['pl_runs']
|
|
# if 'hits' not in away_stats:
|
|
# # logger.info(f'hits not in away_stats')
|
|
# away_stats['hits'] = this_stats[0]['pl_hit']
|
|
# else:
|
|
# # logger.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)
|
|
# logger.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!'
|
|
# )
|
|
#
|
|
# logger.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:
|
|
# logger.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
|
|
# logger.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
|
|
#
|
|
# logger.debug(f'away_stats (in /endgame function)\n\n{away_stats}')
|
|
# logger.debug(f'home_stats (in /endgame function)\n\n{home_stats}')
|
|
# logger.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}')
|
|
#
|
|
# logger.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)
|
|
#
|
|
# logger.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(
|
|
"I dont't see an active game in this channel!"
|
|
)
|
|
return
|
|
|
|
if not this_game.is_pd:
|
|
await interaction.response.send_message(
|
|
"Lineup imports are only supported for PD games right now."
|
|
"Please use the `/setlineup` command."
|
|
)
|
|
return
|
|
|
|
lineup_team = await get_game_team(this_game, interaction.user.id)
|
|
logger.debug(f"read_lineup_command - lineup_team: {lineup_team}")
|
|
if "gauntlet" in this_game.game_type:
|
|
lineup_team = await get_game_team(
|
|
this_game, team_abbrev=f'Gauntlet-{lineup_team["abbrev"]}'
|
|
)
|
|
if lineup_team["id"] not in [this_game.away_team_id, this_game.home_team_id]:
|
|
logger.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
|
|
)
|
|
logger.debug(f"read_lineup_command - existing_lineups:\n{existing_lineups}")
|
|
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(
|
|
"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("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
|
|
|
|
logger.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.initialize_play_plus_embed(this_game)
|
|
)
|
|
except IntegrityError as e:
|
|
logger.debug(
|
|
f"Unable to pull game_state for game_id {this_game.id} until both lineups are in: {e}"
|
|
)
|
|
await interaction.response.send_message(
|
|
"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("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("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):
|
|
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.initialize_play_plus_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(PD_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("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.initialize_play_plus_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.initialize_play_plus_embed(this_game)
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=None, embed=await self.initialize_play_plus_embed(this_game)
|
|
)
|
|
|
|
# @group_substitution.command(name='forfeit-dh', description='Have the pitcher bat in the DH spot')
|
|
# @commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
# async def sub_forfeitdh_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
|
|
#
|
|
|
|
@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("I dont't see an active game in this channel!")
|
|
return
|
|
|
|
response = await ctx.send("Building the scorebug now...")
|
|
|
|
await response.edit(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=include_lineups
|
|
),
|
|
)
|
|
|
|
async def checks_log_interaction(
|
|
self, interaction: discord.Interaction, block_rollback: Optional[bool] = False
|
|
) -> tuple[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 owner_team["id"] not in [this_game.away_team_id, this_game.home_team_id]:
|
|
logger.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:
|
|
logger.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="Looks like your game got hung up there for a second. I just rolled it back a play to "
|
|
"release it. If you have any more issues, let Cal know."
|
|
)
|
|
this_play = get_current_play(this_game.id)
|
|
|
|
if not this_play.pitcher:
|
|
logger.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="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
|
|
|
|
view = Confirm(responders=[interaction.user], timeout=60, label_type="yes")
|
|
question = await interaction.channel.send(
|
|
"Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers cook in some "
|
|
"cases. Are you sure you want to manually run a sub for them?",
|
|
view=view,
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
await question.edit(
|
|
content="~~Whoa there, cowpoke. The AI can automatically make pitcher subs now and will let pitchers "
|
|
"cook in some cases. Are you sure you want to manually run a sub for them?~~\n\nI let Cal "
|
|
"know his stupid AI isn't working.",
|
|
view=None,
|
|
)
|
|
await send_to_channel(
|
|
self.bot,
|
|
"commissioners-office",
|
|
content=f"{interaction.user.display_name} just ran a manual sub here: {question.jump_url}",
|
|
)
|
|
else:
|
|
await question.delete()
|
|
await interaction.edit_original_response(
|
|
content="Jkjkjk, we will let the ai decide when to make subs.",
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
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)
|
|
logger.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="Okay, I'll leave them in!"
|
|
)
|
|
return
|
|
|
|
# new_pitcher = await next_pitcher(this_play, ai_team, self.bot)
|
|
# logger.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)
|
|
|
|
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.initialize_play_plus_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)
|
|
|
|
if flyball_type not in ["a", "c"] and this_play.on_base_code > 0:
|
|
await interaction.edit_original_response(content="Flyball has been logged")
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_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.initialize_play_plus_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)
|
|
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)}*"
|
|
)
|
|
|
|
logger.debug("calling of embed")
|
|
await show_outfield_cards(interaction, this_play)
|
|
logger.debug("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()
|
|
|
|
logger.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="Uncapped single has been logged"
|
|
)
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
|
|
@group_log.command(
|
|
name="frame-pitch",
|
|
description="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)
|
|
logger.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.initialize_play_plus_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)
|
|
this_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 = "*The runner will attempt to advance*"
|
|
else:
|
|
ai_hint = (
|
|
f"*The runner will "
|
|
f"{this_manager.uncapped_advance(4, this_play.starting_outs)}*"
|
|
)
|
|
|
|
logger.debug("calling of embed")
|
|
await show_outfield_cards(interaction, this_play)
|
|
logger.debug("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 {this_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"{this_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"{this_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="Uncapped double has been logged"
|
|
)
|
|
await interaction.channel.send(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_embed(
|
|
this_game, full_length=False
|
|
),
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embed=await self.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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="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.initialize_play_plus_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="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="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="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.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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.initialize_play_plus_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:
|
|
logger.debug(
|
|
f"Undoing play {this_play.id} in Game {this_game.id}: Batter {this_play.batter}"
|
|
)
|
|
undo_play(this_game.id)
|
|
except AttributeError:
|
|
logger.error(f"Could not undo play {this_play.id} in game {this_game.id}")
|
|
|
|
try:
|
|
last_completed = get_latest_play(this_game.id)
|
|
logger.debug(f"Undoing play {last_completed.id} in Game {this_game.id}")
|
|
undo_play(this_game.id)
|
|
except AttributeError:
|
|
logger.error(f"Could not undo second play in game {this_game.id}")
|
|
|
|
latest_play = get_latest_play(this_game.id)
|
|
logger.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.initialize_play_plus_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_legacy(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 = 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(
|
|
"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(
|
|
"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(
|
|
"What was the result of the play?", view=view
|
|
)
|
|
logger.info(f"obc: {this_play.on_base_code}")
|
|
await view.wait()
|
|
|
|
logger.info(f"gameplay - view: {view} / view.value: {view.value}")
|
|
gb_type = view.value
|
|
logger.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(
|
|
"Was the defender playing in?", view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if view.value:
|
|
playing_in = True
|
|
else:
|
|
playing_in = False
|
|
|
|
await question.delete()
|
|
logger.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:
|
|
logger.info("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(
|
|
"What was the result of the play?", view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.delete()
|
|
await interaction.channel.send(
|
|
content="Just logged the x-check! Please log the resulting play to continue (e.g. "
|
|
"'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"
|
|
|
|
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
|
|
elif hit_allowed == "single**":
|
|
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
|
|
else:
|
|
single_onestar(this_play, False)
|
|
if error_allowed == "2 bases":
|
|
advance_runners(this_play.id, 3, True)
|
|
batter_to_base = 3
|
|
elif error_allowed == "1 base" or (
|
|
error_allowed == "Rare Play" and not runner_on_first(this_play)
|
|
):
|
|
single_wellhit(this_play, False)
|
|
batter_to_base = 2
|
|
patch_play(this_play.id, error=True)
|
|
else:
|
|
batter_to_base = 1
|
|
|
|
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(
|
|
"What was the result of the play?", view=view
|
|
)
|
|
logger.info(f"obc: {this_play.on_base_code}")
|
|
await view.wait()
|
|
|
|
logger.info(f"gameplay - view: {view} / view.value: {view.value}")
|
|
gb_type = view.value
|
|
logger.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"
|
|
)
|
|
elif gb_type == "PO":
|
|
single_onestar(this_play)
|
|
elif gb_type == "FO":
|
|
advance_runners(this_play.id, num_bases=1, only_forced=True)
|
|
patch_play(this_play.id, pa=1, ab=1, hit=0, error=1)
|
|
complete_play(this_play.id, batter_to_base=1)
|
|
else:
|
|
view = ButtonOptions(
|
|
responders=[interaction.user],
|
|
labels=["F1", "F2", "F3", None, None],
|
|
)
|
|
question = await interaction.channel.send(
|
|
"What was the result of the play?", view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.delete()
|
|
await interaction.channel.send(
|
|
content="Just logged the x-check! Please log the resulting play to continue (e.g. "
|
|
"'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(
|
|
"What was the result of the play?", view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
await question.edit(
|
|
content="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="**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.initialize_play_plus_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.initialize_play_plus_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
|
|
# )
|
|
# logger.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="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))
|