New show-card dropdown view
Added PlayInitException Added complete_and_post_play for log commands Added many more log plays Add undo-play Added query logging
This commit is contained in:
parent
fc3b407f2d
commit
c3418c4dfd
185
cogs/gameplay.py
185
cogs/gameplay.py
@ -8,14 +8,14 @@ from discord.ext import commands, tasks
|
|||||||
import pygsheets
|
import pygsheets
|
||||||
|
|
||||||
from api_calls import db_get
|
from api_calls import db_get
|
||||||
from command_logic.logic_gameplay import doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, singles
|
from command_logic.logic_gameplay import advance_runners, bunts, doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, hit_by_pitch, homeruns, popouts, show_defense_cards, singles, strikeouts, triples, undo_play, walks
|
||||||
from exceptions import GameNotFoundException, TeamNotFoundException, PlayNotFoundException, GameException
|
from exceptions import GameNotFoundException, TeamNotFoundException, PlayNotFoundException, GameException
|
||||||
from helpers import PD_PLAYERS_ROLE_NAME, team_role, user_has_role, random_gif, random_from_list
|
from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, team_role, user_has_role, random_gif, random_from_list
|
||||||
|
|
||||||
# from in_game import ai_manager
|
# from in_game import ai_manager
|
||||||
from in_game.ai_manager import get_starting_pitcher, get_starting_lineup
|
from in_game.ai_manager import get_starting_pitcher, get_starting_lineup
|
||||||
from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check
|
from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check
|
||||||
from in_game.gameplay_models import Lineup, Session, engine, player_description, select, Game
|
from in_game.gameplay_models import Lineup, Play, Session, engine, player_description, select, Game
|
||||||
from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team, get_game_lineups, get_team_or_none, get_card_or_none
|
from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team, get_game_lineups, get_team_or_none, get_card_or_none
|
||||||
|
|
||||||
from utilities.buttons import Confirm
|
from utilities.buttons import Confirm
|
||||||
@ -49,6 +49,25 @@ class Gameplay(commands.Cog):
|
|||||||
logging.error(msg=error, stack_info=True)
|
logging.error(msg=error, stack_info=True)
|
||||||
await ctx.send(f'{error[:1600]}')
|
await ctx.send(f'{error[:1600]}')
|
||||||
|
|
||||||
|
async def post_play(self, session: Session, interaction: discord.Interaction, this_play: Play, buffer_message: str = None):
|
||||||
|
if buffer_message is not None:
|
||||||
|
await interaction.edit_original_response(
|
||||||
|
content=buffer_message
|
||||||
|
)
|
||||||
|
await interaction.channel.send(
|
||||||
|
content=None,
|
||||||
|
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await interaction.edit_original_response(
|
||||||
|
content=None,
|
||||||
|
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def complete_and_post_play(self, session: Session, interaction: discord.Interaction, this_play: Play, buffer_message: str = None):
|
||||||
|
complete_play(session, this_play)
|
||||||
|
await self.post_play(session, interaction, this_play, buffer_message)
|
||||||
|
|
||||||
group_new_game = app_commands.Group(name='new-game', description='Start a new baseball game')
|
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')
|
@group_new_game.command(name='mlb-campaign', description='Start a new MLB campaign game against an AI')
|
||||||
@ -106,7 +125,7 @@ class Gameplay(commands.Cog):
|
|||||||
ai_team = away_team if away_team.is_ai else home_team
|
ai_team = away_team if away_team.is_ai else home_team
|
||||||
human_team = away_team if home_team.is_ai else away_team
|
human_team = away_team if home_team.is_ai else away_team
|
||||||
|
|
||||||
conflict_games = get_active_games_by_team(session, team_id=human_team.id)
|
conflict_games = get_active_games_by_team(session, team=human_team)
|
||||||
if len(conflict_games) > 0:
|
if len(conflict_games) > 0:
|
||||||
await interaction.edit_original_response(
|
await interaction.edit_original_response(
|
||||||
content=f'Ope. The {human_team.sname} are already playing over in {interaction.guild.get_channel(conflict_games[0].channel_id).mention}'
|
content=f'Ope. The {human_team.sname} are already playing over in {interaction.guild.get_channel(conflict_games[0].channel_id).mention}'
|
||||||
@ -352,69 +371,141 @@ class Gameplay(commands.Cog):
|
|||||||
@group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c')
|
@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']):
|
async def log_flyball(self, interaction: discord.Interaction, flyball_type: Literal['a', 'b', 'ballpark', 'b?', 'c']):
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='flyball')
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log flyball')
|
||||||
|
|
||||||
this_play = await flyballs(session, interaction, this_game, this_play, flyball_type)
|
this_play = await flyballs(session, interaction, this_play, flyball_type)
|
||||||
logging.info(f'log flyball {flyball_type} - this_play: {this_play}')
|
logging.info(f'log flyball {flyball_type} - this_play: {this_play}')
|
||||||
|
|
||||||
complete_play(session, this_play)
|
await self.complete_and_post_play(
|
||||||
|
session,
|
||||||
if this_play.starting_outs + this_play.outs < 3 and ((this_play.on_second and flyball_type == 'b') or (this_play.on_third and flyball_type == '?b')):
|
interaction,
|
||||||
await interaction.edit_original_response(content='Flyball logged')
|
this_play,
|
||||||
await interaction.channel.send(
|
buffer_message='Double logged' if this_play.starting_outs + this_play.outs < 3 and ((this_play.on_second and flyball_type == 'b') or (this_play.on_third and flyball_type == '?b')) else None
|
||||||
content=None,
|
)
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await interaction.edit_original_response(
|
|
||||||
content=None,
|
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
|
||||||
)
|
|
||||||
|
|
||||||
@group_log.command(name='single', description='Singles: *, **, ballpark, uncapped')
|
@group_log.command(name='single', description='Singles: *, **, ballpark, uncapped')
|
||||||
async def log_single(
|
async def log_single(
|
||||||
self, interaction: discord.Interaction, single_type: Literal['*', '**', 'ballpark', 'uncapped']):
|
self, interaction: discord.Interaction, single_type: Literal['*', '**', 'ballpark', 'uncapped']):
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='single')
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log single')
|
||||||
|
|
||||||
this_play = await singles(session, interaction, this_game, this_play, single_type)
|
this_play = await singles(session, interaction, this_play, single_type)
|
||||||
logging.info(f'log single {single_type} - this_play: {this_play}')
|
logging.info(f'log single {single_type} - this_play: {this_play}')
|
||||||
|
|
||||||
complete_play(session, this_play)
|
await self.complete_and_post_play(session, interaction, this_play, buffer_message='Double logged' if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped') else None)
|
||||||
|
|
||||||
if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped'):
|
# complete_play(session, this_play)
|
||||||
await interaction.edit_original_response(content='Single logged')
|
|
||||||
await interaction.channel.send(
|
# if ((this_play.on_first or this_play.on_second) and single_type == 'uncapped'):
|
||||||
content=None,
|
# await interaction.edit_original_response(content='Single logged')
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
# await interaction.channel.send(
|
||||||
)
|
# content=None,
|
||||||
else:
|
# embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
||||||
await interaction.edit_original_response(
|
# )
|
||||||
content=None,
|
# else:
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
# await interaction.edit_original_response(
|
||||||
)
|
# content=None,
|
||||||
|
# embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
||||||
|
# )
|
||||||
|
|
||||||
@group_log.command(name='double', description='Doubles: **, ***, uncapped')
|
@group_log.command(name='double', description='Doubles: **, ***, uncapped')
|
||||||
async def log_double(self, interaction: discord.Interaction, double_type: Literal['**', '***', 'uncapped']):
|
async def log_double(self, interaction: discord.Interaction, double_type: Literal['**', '***', 'uncapped']):
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='double')
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log double')
|
||||||
|
|
||||||
this_play = await doubles(session, interaction, this_game, this_play, double_type)
|
this_play = await doubles(session, interaction, this_play, double_type)
|
||||||
logging.info(f'log double {double_type} - this_play: {this_play}')
|
logging.info(f'log double {double_type} - this_play: {this_play}')
|
||||||
|
|
||||||
complete_play(session, this_play)
|
await self.complete_and_post_play(session, interaction, this_play, buffer_message='Double logged' if (this_play.on_first and double_type == 'uncapped') else None)
|
||||||
|
|
||||||
if (this_play.on_first and double_type == 'uncapped'):
|
@group_log.command(name='triple', description='Triples: no sub-types')
|
||||||
await interaction.edit_original_response(content='Double logged')
|
async def log_triple(self, interaction: discord.Interaction):
|
||||||
await interaction.channel.send(
|
with Session(engine) as session:
|
||||||
content=None,
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log triple')
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
|
||||||
)
|
this_play = await triples(session, interaction, this_play)
|
||||||
else:
|
logging.info(f'log triple - this_play: {this_play}')
|
||||||
await interaction.edit_original_response(
|
|
||||||
content=None,
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
embed=this_play.game.get_scorebug_embed(session, full_length=False, classic=CLASSIC_EMBED)
|
|
||||||
)
|
@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']):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log homerun')
|
||||||
|
|
||||||
|
this_play = await homeruns(session, interaction, this_play, homerun_type)
|
||||||
|
logging.info(f'log homerun {homerun_type} - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='walk', description='Walks: unintentional (default), intentional')
|
||||||
|
async def log_walk(self, interaction: discord.Interaction, walk_type: Literal['unintentional', 'intentional'] = 'unintentional'):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log walk')
|
||||||
|
|
||||||
|
this_play = await walks(session, interaction, this_play, walk_type)
|
||||||
|
logging.info(f'log walk {walk_type} - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='strikeout', description='Strikeout')
|
||||||
|
async def log_strikeout(self, interaction: discord.Interaction):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log strikeout')
|
||||||
|
|
||||||
|
this_play = await strikeouts(session, interaction, this_play)
|
||||||
|
logging.info(f'log strikeout - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='popout', description='Popout')
|
||||||
|
async def log_popout(self, interaction: discord.Interaction):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log popout')
|
||||||
|
|
||||||
|
this_play = await popouts(session, interaction, this_play)
|
||||||
|
logging.info(f'log popout - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='hit-by-pitch', description='Hit by pitch: batter to first; runners advance if forced')
|
||||||
|
async def log_hit_by_pitch(self, interaction: discord.Interaction):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log hit-by-pitch')
|
||||||
|
|
||||||
|
this_play = await hit_by_pitch(session, interaction, this_play)
|
||||||
|
logging.info(f'log hit-by-pitch - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='bunt', description='Hit by pitch: batter to first; runners advance if forced')
|
||||||
|
async def log_sac_bunt(self, interaction: discord.Interaction, bunt_type: Literal['sacrifice', 'bad', 'popout', 'double-play', 'defense']):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log bunt')
|
||||||
|
|
||||||
|
this_play = await bunts(session, interaction, this_play, bunt_type)
|
||||||
|
logging.info(f'log bunt - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.complete_and_post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
@group_log.command(name='undo-play', description='Roll back most recent play from the log')
|
||||||
|
async def log_undo_play_command(self, interaction: discord.Interaction):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log undo-play')
|
||||||
|
|
||||||
|
this_play = undo_play(session, this_play)
|
||||||
|
logging.info(f'log undo-play - this_play: {this_play}')
|
||||||
|
|
||||||
|
await self.post_play(session, interaction, this_play)
|
||||||
|
|
||||||
|
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: DEFENSE_LITERAL):
|
||||||
|
with Session(engine) as session:
|
||||||
|
this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='show-card defense')
|
||||||
|
|
||||||
|
await show_defense_cards(session, interaction, this_play, position)
|
||||||
|
logging.info(f'show-card defense - position: {position}')
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
|
|||||||
@ -4,13 +4,16 @@ import logging
|
|||||||
import discord
|
import discord
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from sqlmodel import Session, select, func
|
from sqlmodel import Session, select, func
|
||||||
|
from sqlalchemy import delete
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from exceptions import *
|
from exceptions import *
|
||||||
|
from helpers import DEFENSE_LITERAL
|
||||||
from in_game.game_helpers import legal_check
|
from in_game.game_helpers import legal_check
|
||||||
from in_game.gameplay_models import Game, Lineup, Team, Play
|
from in_game.gameplay_models import Game, Lineup, Team, Play
|
||||||
from in_game.gameplay_queries import get_card_or_none, get_channel_game_or_none, get_last_team_play, get_one_lineup, get_team_or_none, get_players_last_pa
|
from in_game.gameplay_queries import get_card_or_none, get_channel_game_or_none, get_last_team_play, get_one_lineup, get_sorted_lineups, get_team_or_none, get_players_last_pa
|
||||||
from utilities.buttons import ButtonOptions, Confirm, ask_confirm
|
from utilities.buttons import ButtonOptions, Confirm, ask_confirm
|
||||||
|
from utilities.dropdown import DropdownOptions, DropdownView, SelectViewDefense
|
||||||
from utilities.embeds import image_embed
|
from utilities.embeds import image_embed
|
||||||
from utilities.pages import Pagination
|
from utilities.pages import Pagination
|
||||||
|
|
||||||
@ -307,7 +310,7 @@ async def checks_log_interaction(session: Session, interaction: discord.Interact
|
|||||||
this_play = this_game.current_play_or_none(session)
|
this_play = this_game.current_play_or_none(session)
|
||||||
if this_play is None:
|
if this_play is None:
|
||||||
logging.error(f'{command_name} command: No play found for Game ID {this_game.id} - attempting to initialize play')
|
logging.error(f'{command_name} command: No play found for Game ID {this_game.id} - attempting to initialize play')
|
||||||
this_play = this_game.initialize_play(session)
|
this_play = activate_last_play(session, this_game)
|
||||||
|
|
||||||
this_play.locked = True
|
this_play.locked = True
|
||||||
session.add(this_play)
|
session.add(this_play)
|
||||||
@ -422,11 +425,6 @@ def advance_runners(session: Session, this_play: Play, num_bases: int, is_error:
|
|||||||
else:
|
else:
|
||||||
this_play.on_first_final = 1
|
this_play.on_first_final = 1
|
||||||
|
|
||||||
if num_bases == 4:
|
|
||||||
this_play.batter_final = 4
|
|
||||||
this_play.rbi += 1
|
|
||||||
this_play.run = 1
|
|
||||||
|
|
||||||
return this_play
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
@ -511,10 +509,11 @@ async def show_outfield_cards(session: Session, interaction: discord.Interaction
|
|||||||
return [lf, cf, rf][page_num]
|
return [lf, cf, rf][page_num]
|
||||||
|
|
||||||
|
|
||||||
async def flyballs(session: Session, interaction: discord.Interaction, this_game: Game, this_play: Play, flyball_type: Literal['a', 'ballpark', 'b', 'b?', 'c']) -> Play:
|
async def flyballs(session: Session, interaction: discord.Interaction, this_play: Play, flyball_type: Literal['a', 'ballpark', 'b', 'b?', 'c']) -> Play:
|
||||||
"""
|
"""
|
||||||
Commits this_play
|
Commits this_play
|
||||||
"""
|
"""
|
||||||
|
this_game = this_play.game
|
||||||
num_outs = 1
|
num_outs = 1
|
||||||
|
|
||||||
if flyball_type == 'a':
|
if flyball_type == 'a':
|
||||||
@ -639,7 +638,8 @@ async def flyballs(session: Session, interaction: discord.Interaction, this_game
|
|||||||
return this_play
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
async def check_uncapped_advance(session: Session, interaction: discord.Interaction, this_game: Game, this_play: Play, lead_runner: Lineup, lead_base: int, trail_runner: Lineup, trail_base: int):
|
async def check_uncapped_advance(session: Session, interaction: discord.Interaction, this_play: Play, lead_runner: Lineup, lead_base: int, trail_runner: Lineup, trail_base: int):
|
||||||
|
this_game = this_play.game
|
||||||
outfielder = await show_outfield_cards(session, interaction, this_play)
|
outfielder = await show_outfield_cards(session, interaction, this_play)
|
||||||
logging.info(f'throw from {outfielder.player.name_with_desc}')
|
logging.info(f'throw from {outfielder.player.name_with_desc}')
|
||||||
def_team = this_play.pitcher.team
|
def_team = this_play.pitcher.team
|
||||||
@ -919,11 +919,11 @@ async def check_uncapped_advance(session: Session, interaction: discord.Interact
|
|||||||
return this_play
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
async def singles(session: Session, interaction: discord.Interaction, this_game: Game, this_play: Play, single_type: Literal['*', '**', 'ballpark', 'uncapped']) -> Play:
|
async def singles(session: Session, interaction: discord.Interaction, this_play: Play, single_type: Literal['*', '**', 'ballpark', 'uncapped']) -> Play:
|
||||||
"""
|
"""
|
||||||
Commits this_play
|
Commits this_play
|
||||||
"""
|
"""
|
||||||
this_play.pa, this_play.ab, this_play.hit, this_play.batter_final = 1, 1, 1, 1
|
this_play.hit, this_play.batter_final = 1, 1
|
||||||
|
|
||||||
if single_type == '**':
|
if single_type == '**':
|
||||||
advance_runners(session, this_play, num_bases=2)
|
advance_runners(session, this_play, num_bases=2)
|
||||||
@ -954,7 +954,7 @@ async def singles(session: Session, interaction: discord.Interaction, this_game:
|
|||||||
trail_runner = this_play.batter
|
trail_runner = this_play.batter
|
||||||
trail_base = 2
|
trail_base = 2
|
||||||
|
|
||||||
this_play = await check_uncapped_advance(session, interaction, this_game, this_play, lead_runner, lead_base, trail_runner, trail_base)
|
this_play = await check_uncapped_advance(session, interaction, this_play, lead_runner, lead_base, trail_runner, trail_base)
|
||||||
|
|
||||||
session.add(this_play)
|
session.add(this_play)
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -963,7 +963,7 @@ async def singles(session: Session, interaction: discord.Interaction, this_game:
|
|||||||
return this_play
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
async def doubles(session: Session, interaction: discord.Interaction, this_game: Game, this_play: Play, double_type: Literal['**', '***', 'uncapped']) -> Play:
|
async def doubles(session: Session, interaction: discord.Interaction, this_play: Play, double_type: Literal['**', '***', 'uncapped']) -> Play:
|
||||||
"""
|
"""
|
||||||
Commits this_play
|
Commits this_play
|
||||||
"""
|
"""
|
||||||
@ -979,7 +979,7 @@ async def doubles(session: Session, interaction: discord.Interaction, this_game:
|
|||||||
this_play = advance_runners(session, this_play, num_bases=2)
|
this_play = advance_runners(session, this_play, num_bases=2)
|
||||||
|
|
||||||
if this_play.on_first:
|
if this_play.on_first:
|
||||||
this_play = await check_uncapped_advance(session, interaction, this_game, this_play, lead_runner=this_play.on_first, lead_base=4, trail_runner=this_play.batter, trail_base=3)
|
this_play = await check_uncapped_advance(session, interaction, this_play, lead_runner=this_play.on_first, lead_base=4, trail_runner=this_play.batter, trail_base=3)
|
||||||
|
|
||||||
session.add(this_play)
|
session.add(this_play)
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -987,3 +987,166 @@ async def doubles(session: Session, interaction: discord.Interaction, this_game:
|
|||||||
session.refresh(this_play)
|
session.refresh(this_play)
|
||||||
return this_play
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def triples(session: Session, interaction: discord.Interaction, this_play: Play):
|
||||||
|
"""
|
||||||
|
Commits this play
|
||||||
|
"""
|
||||||
|
this_play.hit, this_play.triple, this_play.batter_final = 1, 1, 3
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=3)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def homeruns(session: Session, interaction: discord.Interaction, this_play: Play, homerun_type: Literal['ballpark', 'no-doubt']):
|
||||||
|
this_play.hit, this_play.homerun, this_play.batter_final, this_play.rbi, this_play.run = 1, 1, 4, 1, 1
|
||||||
|
this_play.bphr = 1 if homerun_type == 'ballpark' else 0
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=4)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def walks(session: Session, interaction: discord.Interaction, this_play: Play, walk_type: Literal['unintentional', 'intentional'] = 'unintentional'):
|
||||||
|
this_play.ab, this_play.bb, this_play.batter_final = 0, 1, 1
|
||||||
|
this_play.ibb = 1 if walk_type == 'intentional' else 0
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=1, only_forced=True)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def strikeouts(session: Session, interaction: discord.Interaction, this_play: Play):
|
||||||
|
this_play.so, this_play.outs = 1, 1
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=0)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def popouts(session: Session, interaction: discord.Interaction, this_play: Play):
|
||||||
|
this_play.outs = 1
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=0)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def hit_by_pitch(session: Session, interaction: discord.Interaction, this_play: Play):
|
||||||
|
this_play.ab, this_play.hbp = 0, 1
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=1, only_forced=True)
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def bunts(session: Session, interaction: discord.Interaction, this_play: Play, bunt_type: Literal['sacrifice', 'bad', 'popout', 'double-play', 'defense']):
|
||||||
|
this_play.ab = 1 if bunt_type != 'sacrifice' else 0
|
||||||
|
this_play.sac = 1 if bunt_type != 'sacrifice' else 0
|
||||||
|
|
||||||
|
if bunt_type == 'sacrifice':
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=1)
|
||||||
|
elif bunt_type == 'popout':
|
||||||
|
this_play = advance_runners(session, this_play, num_bases=0)
|
||||||
|
else:
|
||||||
|
log_exception(KeyError, f'Bunt type {bunt_type} is not yet implemented')
|
||||||
|
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
session.refresh(this_play)
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
def activate_last_play(session: Session, this_game: Game) -> Play:
|
||||||
|
p_query = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(1)).all()
|
||||||
|
|
||||||
|
this_play = complete_play(session, p_query[0])
|
||||||
|
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
def undo_play(session: Session, this_play: Play):
|
||||||
|
this_game = this_play.game
|
||||||
|
|
||||||
|
last_two_plays = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(2)).all()
|
||||||
|
|
||||||
|
for play in last_two_plays:
|
||||||
|
for runner, to_base in [(play.on_first, play.on_first_final), (play.on_second, play.on_second_final), (play.on_third, play.on_third_final)]:
|
||||||
|
if to_base == 4:
|
||||||
|
last_pa = get_players_last_pa(session, runner)
|
||||||
|
last_pa.run, last_pa.e_run = 0, 0
|
||||||
|
session.add(last_pa)
|
||||||
|
|
||||||
|
last_two_ids = [last_two_plays[0].id, last_two_plays[1].id]
|
||||||
|
logging.warning(f'Deleting plays: {last_two_ids}')
|
||||||
|
session.exec(delete(Play).where(Play.id.in_(last_two_ids)))
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
this_play = this_game.initialize_play(session)
|
||||||
|
logging.info(f'Initialized play: {this_play.id}')
|
||||||
|
except PlayInitException:
|
||||||
|
this_play = activate_last_play(session, this_game)
|
||||||
|
logging.info(f'Re-activated play: {this_play.id}')
|
||||||
|
|
||||||
|
return this_play
|
||||||
|
|
||||||
|
|
||||||
|
async def show_defense_cards(session: Session, interaction: discord.Interaction, this_play: Play, first_position: DEFENSE_LITERAL):
|
||||||
|
position_map = {
|
||||||
|
'Pitcher': 'P',
|
||||||
|
'Catcher': 'C',
|
||||||
|
'First Base': '1B',
|
||||||
|
'Second Base': '2B',
|
||||||
|
'Third Base': '3B',
|
||||||
|
'Shortstop': 'SS',
|
||||||
|
'Left Field': 'LF',
|
||||||
|
'Center Field': 'CF',
|
||||||
|
'Right Field': 'RF'
|
||||||
|
}
|
||||||
|
this_position = position_map[first_position]
|
||||||
|
|
||||||
|
sorted_lineups = get_sorted_lineups(session, this_play.game, this_play.pitcher.team)
|
||||||
|
select_player_options = [
|
||||||
|
discord.SelectOption(label=f'{x.position} - {x.player.name}', value=f'{x.id}', default=this_position == x.position) for x in sorted_lineups
|
||||||
|
]
|
||||||
|
|
||||||
|
this_lineup = get_one_lineup(session, this_play.game, this_play.pitcher.team, position=this_position)
|
||||||
|
player_embed = image_embed(
|
||||||
|
image_url=this_lineup.player.image,
|
||||||
|
color=this_play.pitcher.team.color,
|
||||||
|
author_name=this_play.pitcher.team.lname,
|
||||||
|
author_icon=this_play.pitcher.team.logo
|
||||||
|
)
|
||||||
|
player_dropdown = SelectViewDefense(
|
||||||
|
options=select_player_options,
|
||||||
|
this_play=this_play,
|
||||||
|
base_embed=player_embed,
|
||||||
|
session=session,
|
||||||
|
sorted_lineups=sorted_lineups
|
||||||
|
)
|
||||||
|
dropdown_view = DropdownView(dropdown_objects=[player_dropdown], timeout=60)
|
||||||
|
|
||||||
|
await interaction.edit_original_response(content=None, embed=player_embed, view=dropdown_view)
|
||||||
|
|
||||||
|
|
||||||
@ -34,3 +34,7 @@ class TeamNotFoundException(GameException):
|
|||||||
|
|
||||||
class PlayNotFoundException(GameException):
|
class PlayNotFoundException(GameException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PlayInitException(GameException):
|
||||||
|
pass
|
||||||
|
|||||||
@ -244,6 +244,7 @@ SELECT_CARDSET_OPTIONS = [
|
|||||||
discord.SelectOption(label='2012 Season', value='7')
|
discord.SelectOption(label='2012 Season', value='7')
|
||||||
]
|
]
|
||||||
ACTIVE_EVENT_LITERAL = Literal['1998 Season']
|
ACTIVE_EVENT_LITERAL = Literal['1998 Season']
|
||||||
|
DEFENSE_LITERAL = Literal['Pitcher', 'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', 'Center Field', 'Right Field']
|
||||||
|
|
||||||
|
|
||||||
class Question:
|
class Question:
|
||||||
|
|||||||
@ -128,7 +128,7 @@ class Game(SQLModel, table=True):
|
|||||||
return f'{pri_cardsets}{back_cardsets}'
|
return f'{pri_cardsets}{back_cardsets}'
|
||||||
|
|
||||||
def current_play_or_none(self, session: Session):
|
def current_play_or_none(self, session: Session):
|
||||||
this_play = session.exec(select(Play).where(Play.game == self).order_by(Play.id.desc()).limit(1)).all()
|
this_play = session.exec(select(Play).where(Play.game == self, Play.complete == False).order_by(Play.id.desc()).limit(1)).all()
|
||||||
if len(this_play) == 1:
|
if len(this_play) == 1:
|
||||||
return this_play[0]
|
return this_play[0]
|
||||||
else:
|
else:
|
||||||
@ -231,6 +231,10 @@ class Game(SQLModel, table=True):
|
|||||||
if existing_play is not None:
|
if existing_play is not None:
|
||||||
return existing_play
|
return existing_play
|
||||||
|
|
||||||
|
all_plays = session.exec(select(func.count(Play.id)).where(Play.game == self)).one()
|
||||||
|
if all_plays > 0:
|
||||||
|
raise PlayInitException(f'{all_plays} plays for game {self.id} already exist, but all are complete.')
|
||||||
|
|
||||||
leadoff_batter, home_pitcher, home_catcher = None, None, None
|
leadoff_batter, home_pitcher, home_catcher = None, None, None
|
||||||
home_positions, away_positions = [], []
|
home_positions, away_positions = [], []
|
||||||
for line in [x for x in self.lineups if x.active]:
|
for line in [x for x in self.lineups if x.active]:
|
||||||
@ -796,9 +800,7 @@ class Play(PlayBase, table=True):
|
|||||||
|
|
||||||
# Defensive Alignment
|
# Defensive Alignment
|
||||||
if self.on_third and self.starting_outs < 2:
|
if self.on_third and self.starting_outs < 2:
|
||||||
if self.on_first:
|
if abs(self.away_score - self.home_score) <= 3:
|
||||||
ai_note += f'- play the corners in\n'
|
|
||||||
elif abs(self.away_score - self.home_score) <= 3:
|
|
||||||
ai_note += f'- play the whole infield in\n'
|
ai_note += f'- play the whole infield in\n'
|
||||||
else:
|
else:
|
||||||
ai_note += f'- play the corners in\n'
|
ai_note += f'- play the corners in\n'
|
||||||
|
|||||||
@ -8,10 +8,12 @@ from exceptions import log_exception, PlayNotFoundException
|
|||||||
|
|
||||||
|
|
||||||
def get_games_by_channel(session: Session, channel_id: int) -> list[Game]:
|
def get_games_by_channel(session: Session, channel_id: int) -> list[Game]:
|
||||||
|
logging.info(f'Getting games in channel {channel_id}')
|
||||||
return session.exec(select(Game).where(Game.channel_id == channel_id, Game.active)).all()
|
return session.exec(select(Game).where(Game.channel_id == channel_id, Game.active)).all()
|
||||||
|
|
||||||
|
|
||||||
def get_channel_game_or_none(session: Session, channel_id: int) -> Game | None:
|
def get_channel_game_or_none(session: Session, channel_id: int) -> Game | None:
|
||||||
|
logging.info(f'Getting one game from channel {channel_id}')
|
||||||
all_games = get_games_by_channel(session, channel_id)
|
all_games = get_games_by_channel(session, channel_id)
|
||||||
if len(all_games) > 1:
|
if len(all_games) > 1:
|
||||||
err = 'Too many games found in get_channel_game_or_none'
|
err = 'Too many games found in get_channel_game_or_none'
|
||||||
@ -22,12 +24,14 @@ def get_channel_game_or_none(session: Session, channel_id: int) -> Game | None:
|
|||||||
return all_games[0]
|
return all_games[0]
|
||||||
|
|
||||||
|
|
||||||
def get_active_games_by_team(session: Session, team_id: int) -> list[Game]:
|
def get_active_games_by_team(session: Session, team: Team) -> list[Game]:
|
||||||
return session.exec(select(Game).where(Game.active, or_(Game.away_team_id == team_id, Game.home_team_id == team_id))).all()
|
logging.info(f'Getting game for team {team.lname}')
|
||||||
|
return session.exec(select(Game).where(Game.active, or_(Game.away_team_id == team.id, Game.home_team_id == team.id))).all()
|
||||||
|
|
||||||
|
|
||||||
async def get_team_or_none(
|
async def get_team_or_none(
|
||||||
session: Session, team_id: int | None = None, gm_id: int | None = None, team_abbrev: str | None = None, skip_cache: bool = False) -> Team | None:
|
session: Session, team_id: int | None = None, gm_id: int | None = None, team_abbrev: str | None = None, skip_cache: bool = False) -> Team | None:
|
||||||
|
logging.info(f'Getting team or none / team_id: {team_id} / gm_id: {gm_id} / team_abbrev: {team_abbrev} / skip_cache: {skip_cache}')
|
||||||
if team_id is None and gm_id is None and team_abbrev is None:
|
if team_id is None and gm_id is None and team_abbrev is None:
|
||||||
err = 'One of "team_id", "gm_id", or "team_abbrev" must be included in search'
|
err = 'One of "team_id", "gm_id", or "team_abbrev" must be included in search'
|
||||||
logging.error(f'gameplay_models - get_team - {err}')
|
logging.error(f'gameplay_models - get_team - {err}')
|
||||||
@ -120,6 +124,7 @@ async def get_player_or_none(session: Session, player_id: int, skip_cache: bool
|
|||||||
|
|
||||||
|
|
||||||
def get_player_id_from_dict(json_data: dict) -> int:
|
def get_player_id_from_dict(json_data: dict) -> int:
|
||||||
|
logging.info(f'Getting player from dict {json_data}')
|
||||||
if 'player_id' in json_data:
|
if 'player_id' in json_data:
|
||||||
return json_data['player_id']
|
return json_data['player_id']
|
||||||
elif 'id' in json_data:
|
elif 'id' in json_data:
|
||||||
@ -130,6 +135,7 @@ def get_player_id_from_dict(json_data: dict) -> int:
|
|||||||
|
|
||||||
|
|
||||||
async def get_or_create_ai_card(session: Session, player: Player, team: Team, skip_cache: bool = False, dev_mode: bool = False) -> Card:
|
async def get_or_create_ai_card(session: Session, player: Player, team: Team, skip_cache: bool = False, dev_mode: bool = False) -> Card:
|
||||||
|
logging.info(f'Getting or creating card for {player.name_with_desc} on the {team.sname}')
|
||||||
if not team.is_ai:
|
if not team.is_ai:
|
||||||
err = f'Cannot create AI cards for human teams'
|
err = f'Cannot create AI cards for human teams'
|
||||||
logging.error(f'gameplay_models - get_or_create_ai_card: {err}')
|
logging.error(f'gameplay_models - get_or_create_ai_card: {err}')
|
||||||
@ -196,6 +202,7 @@ async def get_or_create_ai_card(session: Session, player: Player, team: Team, sk
|
|||||||
|
|
||||||
|
|
||||||
async def get_card_or_none(session: Session, card_id: int, skip_cache: bool = False) -> Card | None:
|
async def get_card_or_none(session: Session, card_id: int, skip_cache: bool = False) -> Card | None:
|
||||||
|
logging.info(f'Getting card {card_id}')
|
||||||
if not skip_cache:
|
if not skip_cache:
|
||||||
this_card = session.get(Card, card_id)
|
this_card = session.get(Card, card_id)
|
||||||
|
|
||||||
@ -236,6 +243,7 @@ async def get_card_or_none(session: Session, card_id: int, skip_cache: bool = Fa
|
|||||||
|
|
||||||
|
|
||||||
def get_game_lineups(session: Session, this_game: Game, specific_team: Team = None, is_active: bool = None) -> list[Lineup]:
|
def get_game_lineups(session: Session, this_game: Game, specific_team: Team = None, is_active: bool = None) -> list[Lineup]:
|
||||||
|
logging.info(f'Getting lineups for game {this_game.id} / specific_team: {specific_team} / is_active: {is_active}')
|
||||||
st = select(Lineup).where(Lineup.game == this_game)
|
st = select(Lineup).where(Lineup.game == this_game)
|
||||||
|
|
||||||
if specific_team is not None:
|
if specific_team is not None:
|
||||||
@ -247,6 +255,7 @@ def get_game_lineups(session: Session, this_game: Game, specific_team: Team = No
|
|||||||
|
|
||||||
|
|
||||||
def get_players_last_pa(session: Session, lineup_member: Lineup, none_okay: bool = False):
|
def get_players_last_pa(session: Session, lineup_member: Lineup, none_okay: bool = False):
|
||||||
|
logging.info(f'Getting last AB for {lineup_member.player.name_with_desc} on the {lineup_member.team.lname}')
|
||||||
last_pa = session.exec(select(Play).where(Play.game == lineup_member.game, Play.batter == lineup_member).order_by(Play.id.desc()).limit(1)).all()
|
last_pa = session.exec(select(Play).where(Play.game == lineup_member.game, Play.batter == lineup_member).order_by(Play.id.desc()).limit(1)).all()
|
||||||
if len(last_pa) == 1:
|
if len(last_pa) == 1:
|
||||||
return last_pa[0]
|
return last_pa[0]
|
||||||
@ -258,6 +267,7 @@ def get_players_last_pa(session: Session, lineup_member: Lineup, none_okay: bool
|
|||||||
|
|
||||||
|
|
||||||
def get_one_lineup(session: Session, this_game: Game, this_team: Team, active: bool = True, position: str = None, batting_order: int = None) -> Lineup:
|
def get_one_lineup(session: Session, this_game: Game, this_team: Team, active: bool = True, position: str = None, batting_order: int = None) -> Lineup:
|
||||||
|
logging.info(f'Getting one lineup / this_game: {this_game.id} / this_team: {this_team.lname} / active: {active}, position: {position}, batting_order: {batting_order}')
|
||||||
if position is None and batting_order is None:
|
if position is None and batting_order is None:
|
||||||
raise KeyError('Position or batting order must be provided for get_one_lineup')
|
raise KeyError('Position or batting order must be provided for get_one_lineup')
|
||||||
|
|
||||||
@ -271,6 +281,7 @@ def get_one_lineup(session: Session, this_game: Game, this_team: Team, active: b
|
|||||||
|
|
||||||
|
|
||||||
def get_last_team_play(session: Session, this_game: Game, this_team: Team, none_okay: bool = False):
|
def get_last_team_play(session: Session, this_game: Game, this_team: Team, none_okay: bool = False):
|
||||||
|
logging.info(f'Getting last play for the {this_team.lname} in game {this_game.id}')
|
||||||
last_play = session.exec(select(Play).join(Lineup, onclause=Lineup.id == Play.batter_id).where(Play.game == this_game, Lineup.team == this_team).order_by(Play.id.desc()).limit(1)).all()
|
last_play = session.exec(select(Play).join(Lineup, onclause=Lineup.id == Play.batter_id).where(Play.game == this_game, Lineup.team == this_team).order_by(Play.id.desc()).limit(1)).all()
|
||||||
|
|
||||||
if len(last_play) == 1:
|
if len(last_play) == 1:
|
||||||
@ -280,3 +291,14 @@ def get_last_team_play(session: Session, this_game: Game, this_team: Team, none_
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
log_exception(PlayNotFoundException, f'No last play found for the {this_team.sname}')
|
log_exception(PlayNotFoundException, f'No last play found for the {this_team.sname}')
|
||||||
|
|
||||||
|
|
||||||
|
def get_sorted_lineups(session: Session, this_game: Game, this_team: Team) -> list[Lineup]:
|
||||||
|
logging.info(f'Getting sorted lineups for the {this_team.lname} in game {this_game.id}')
|
||||||
|
custom_order = {'P': 1, 'C': 2, '1B': 3, '2B': 4, '3B': 5, 'SS': 6, 'LF': 7, 'CF': 8, 'RF': 9}
|
||||||
|
|
||||||
|
all_lineups = session.exec(select(Lineup).where(Lineup.game == this_game, Lineup.active == True, Lineup.team == this_team)).all()
|
||||||
|
|
||||||
|
sorted_lineups = sorted(all_lineups, key=lambda x: custom_order.get(x.position, float('inf')))
|
||||||
|
return sorted_lineups
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from sqlmodel import Session, select, func
|
from sqlmodel import Session, select, func
|
||||||
|
|
||||||
from command_logic.logic_gameplay import advance_runners, get_obc, get_re24, get_wpa, complete_play, log_run_scored
|
from command_logic.logic_gameplay import advance_runners, doubles, get_obc, get_re24, get_wpa, complete_play, log_run_scored, strikeouts
|
||||||
from in_game.gameplay_models import Lineup, Play
|
from in_game.gameplay_models import Lineup, Play
|
||||||
from tests.factory import session_fixture, Game
|
from tests.factory import session_fixture, Game
|
||||||
|
|
||||||
@ -35,6 +35,7 @@ def test_advance_runners(session: Session):
|
|||||||
assert play_3.on_second is None
|
assert play_3.on_second is None
|
||||||
assert play_3.on_first is not None
|
assert play_3.on_first is not None
|
||||||
|
|
||||||
|
|
||||||
def test_get_obc():
|
def test_get_obc():
|
||||||
assert get_obc() == 0
|
assert get_obc() == 0
|
||||||
assert get_obc(on_first=True) == 1
|
assert get_obc(on_first=True) == 1
|
||||||
@ -161,5 +162,35 @@ def test_log_run_scored(session: Session):
|
|||||||
assert e_runs == 1
|
assert e_runs == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_strikeouts(session: Session):
|
||||||
|
game_1 = session.get(Game, 1)
|
||||||
|
play_1 = session.get(Play, 1)
|
||||||
|
|
||||||
|
play_1 = await strikeouts(session, None, game_1, play_1)
|
||||||
|
|
||||||
|
assert play_1.so == 1
|
||||||
|
assert play_1.outs == 1
|
||||||
|
assert play_1.batter_final is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_doubles(session: Session):
|
||||||
|
game_1 = session.get(Game, 1)
|
||||||
|
play_1 = session.get(Play, 1)
|
||||||
|
play_1.hit, play_1.batter_final = 1, 1
|
||||||
|
play_2 = complete_play(session, play_1)
|
||||||
|
|
||||||
|
assert play_2.play_num == 2
|
||||||
|
|
||||||
|
play_2_ghost_1 = await doubles(session, None, game_1, play_2, double_type='***')
|
||||||
|
|
||||||
|
assert play_2_ghost_1.double == 1
|
||||||
|
assert play_2_ghost_1.on_first_final == 4
|
||||||
|
assert play_2_ghost_1.rbi == 1
|
||||||
|
|
||||||
|
play_2_ghost_2 = await doubles(session, None, game_1, play_2, double_type='**')
|
||||||
|
|
||||||
|
assert play_2_ghost_2.double == 1
|
||||||
|
assert play_2_ghost_2.rbi == 0
|
||||||
|
assert play_2_ghost_2.on_first_final == 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -159,7 +159,8 @@ def session_fixture():
|
|||||||
catcher=all_lineups[10],
|
catcher=all_lineups[10],
|
||||||
pa=1,
|
pa=1,
|
||||||
so=1,
|
so=1,
|
||||||
outs=1
|
outs=1,
|
||||||
|
complete=True
|
||||||
)
|
)
|
||||||
game_1_play_2 = Play(
|
game_1_play_2 = Play(
|
||||||
game=game_1,
|
game=game_1,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from sqlalchemy import delete as sadelete
|
|||||||
from sqlalchemy.sql.functions import sum, count
|
from sqlalchemy.sql.functions import sum, count
|
||||||
from sqlmodel import Session, delete
|
from sqlmodel import Session, delete
|
||||||
|
|
||||||
|
from command_logic.logic_gameplay import complete_play, singles, undo_play
|
||||||
from in_game.gameplay_models import Game, Lineup, GameCardsetLink, Play, select
|
from in_game.gameplay_models import Game, Lineup, GameCardsetLink, Play, select
|
||||||
from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team
|
from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team
|
||||||
from tests.factory import session_fixture
|
from tests.factory import session_fixture
|
||||||
@ -138,6 +139,17 @@ def test_sum_function(session: Session):
|
|||||||
assert False == False
|
assert False == False
|
||||||
|
|
||||||
|
|
||||||
|
def test_current_play_or_none(session: Session):
|
||||||
|
game_1 = session.get(Game, 1)
|
||||||
|
this_play = game_1.initialize_play(session)
|
||||||
|
|
||||||
|
assert this_play.play_num == 2
|
||||||
|
|
||||||
|
this_play.complete = True
|
||||||
|
session.add(this_play)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
def test_initialize_play(session: Session):
|
def test_initialize_play(session: Session):
|
||||||
game_1 = session.get(Game, 1)
|
game_1 = session.get(Game, 1)
|
||||||
game_3 = session.get(Game, 3)
|
game_3 = session.get(Game, 3)
|
||||||
@ -156,3 +168,35 @@ def test_initialize_play(session: Session):
|
|||||||
assert g3_play.starting_outs == 0
|
assert g3_play.starting_outs == 0
|
||||||
assert len(play_count) == 3
|
assert len(play_count) == 3
|
||||||
|
|
||||||
|
|
||||||
|
async def test_undo_play(session: Session):
|
||||||
|
game_1 = session.get(Game, 1)
|
||||||
|
this_play = game_1.initialize_play(session)
|
||||||
|
|
||||||
|
assert this_play.play_num == 2
|
||||||
|
|
||||||
|
all_play_ids = session.exec(select(Play.id, Play.play_num).where(Play.game == game_1)).all()
|
||||||
|
|
||||||
|
assert len(all_play_ids) == 2
|
||||||
|
assert all_play_ids[0][0] == 1
|
||||||
|
assert all_play_ids[1][1] == 2
|
||||||
|
|
||||||
|
await singles(session, None, this_play, '*')
|
||||||
|
play_3 = complete_play(session, this_play)
|
||||||
|
|
||||||
|
await singles(session, None, play_3, '*')
|
||||||
|
play_4 = complete_play(session, play_3)
|
||||||
|
on_second_play_4 = play_4.on_second
|
||||||
|
|
||||||
|
await singles(session, None, play_4, '*')
|
||||||
|
play_5 = complete_play(session, play_4)
|
||||||
|
|
||||||
|
assert len(play_5.game.plays) == 5
|
||||||
|
assert play_5.on_base_code == 7
|
||||||
|
|
||||||
|
new_play = undo_play(session, this_play)
|
||||||
|
|
||||||
|
assert len(new_play.game.plays) == 4
|
||||||
|
assert new_play.play_num == 4
|
||||||
|
assert new_play.on_second == on_second_play_4
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import pytest
|
|||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
|
||||||
from in_game.gameplay_models import Game, Lineup
|
from in_game.gameplay_models import Game, Lineup
|
||||||
from in_game.gameplay_queries import get_game_lineups, get_one_lineup
|
from in_game.gameplay_queries import get_game_lineups, get_one_lineup, get_sorted_lineups
|
||||||
from tests.factory import session_fixture
|
from tests.factory import session_fixture
|
||||||
|
|
||||||
|
|
||||||
@ -60,13 +60,20 @@ def test_get_one_lineup(session: Session):
|
|||||||
assert str(exc_info) == "<ExceptionInfo KeyError('Position or batting order must be provided for get_one_lineup') tblen=2>"
|
assert str(exc_info) == "<ExceptionInfo KeyError('Position or batting order must be provided for get_one_lineup') tblen=2>"
|
||||||
|
|
||||||
|
|
||||||
# def test_lineup_substitution(session: Session, new_games_with_lineups: list[Game]):
|
def test_order_lineups_by_position(session: Session):
|
||||||
# game_1 = new_games_with_lineups[0]
|
this_game = session.get(Game, 1)
|
||||||
# game_2 = new_games_with_lineups[1]
|
all_lineups = get_sorted_lineups(session, this_game, this_game.home_team)
|
||||||
|
|
||||||
|
assert all_lineups[0].position == 'P'
|
||||||
|
assert all_lineups[1].position == 'C'
|
||||||
|
assert all_lineups[2].position == '1B'
|
||||||
|
assert all_lineups[3].position == '2B'
|
||||||
|
assert all_lineups[4].position == '3B'
|
||||||
|
assert all_lineups[5].position == 'SS'
|
||||||
|
assert all_lineups[6].position == 'LF'
|
||||||
|
assert all_lineups[7].position == 'CF'
|
||||||
|
assert all_lineups[8].position == 'RF'
|
||||||
|
|
||||||
# session.add(game_1)
|
|
||||||
# session.add(game_2)
|
|
||||||
# session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from sqlmodel import Session, select, func
|
from sqlmodel import Session, select, func
|
||||||
|
|
||||||
from command_logic.logic_gameplay import complete_play, singles
|
from command_logic.logic_gameplay import complete_play, singles, undo_play
|
||||||
from db_calls_gameplay import advance_runners
|
from db_calls_gameplay import advance_runners
|
||||||
from in_game.gameplay_models import Lineup, Play, Game
|
from in_game.gameplay_models import Lineup, Play, Game
|
||||||
from in_game.gameplay_queries import get_last_team_play
|
from in_game.gameplay_queries import get_last_team_play
|
||||||
@ -77,3 +77,33 @@ def test_query_scalars(session: Session):
|
|||||||
|
|
||||||
assert outs == 1
|
assert outs == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_undo_play(session: Session):
|
||||||
|
game_1 = session.get(Game, 1)
|
||||||
|
play_2 = game_1.initialize_play(session)
|
||||||
|
|
||||||
|
assert play_2.play_num == 2
|
||||||
|
|
||||||
|
play_2 = await singles(session, None, play_2, single_type='*')
|
||||||
|
play_3 = complete_play(session, play_2)
|
||||||
|
|
||||||
|
assert play_3.play_num == 3
|
||||||
|
assert play_3.on_first == play_2.batter
|
||||||
|
|
||||||
|
play_3 = await singles(session, None, play_3, single_type='**')
|
||||||
|
play_4 = complete_play(session, play_3)
|
||||||
|
all_plays = session.exec(select(Play).where(Play.game == game_1)).all()
|
||||||
|
|
||||||
|
assert play_4.play_num == 4
|
||||||
|
assert play_4.on_first == play_3.batter
|
||||||
|
assert len(all_plays) == 4
|
||||||
|
|
||||||
|
undone_play = undo_play(session, play_4)
|
||||||
|
|
||||||
|
assert undone_play.play_num == 3
|
||||||
|
|
||||||
|
all_plays = session.exec(select(Play).where(Play.game == game_1)).all()
|
||||||
|
|
||||||
|
assert len(all_plays) == 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
import discord
|
import discord
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
class DropdownOption(discord.ui.Select):
|
from sqlmodel import Session
|
||||||
|
|
||||||
|
from in_game.gameplay_models import Lineup, Play
|
||||||
|
from in_game.gameplay_queries import get_sorted_lineups
|
||||||
|
|
||||||
|
class DropdownOptions(discord.ui.Select):
|
||||||
def __init__(self, option_list: list, placeholder: str = 'Make your selection', min_values: int = 1, max_values: int = 1, callback=None):
|
def __init__(self, option_list: list, placeholder: str = 'Make your selection', min_values: int = 1, max_values: int = 1, callback=None):
|
||||||
# Set the options that will be presented inside the dropdown
|
# Set the options that will be presented inside the dropdown
|
||||||
# options = [
|
# options = [
|
||||||
@ -38,9 +43,124 @@ class DropdownView(discord.ui.View):
|
|||||||
"""
|
"""
|
||||||
https://discordpy.readthedocs.io/en/latest/interactions/api.html#select
|
https://discordpy.readthedocs.io/en/latest/interactions/api.html#select
|
||||||
"""
|
"""
|
||||||
def __init__(self, dropdown_objects: list[DropdownOption], timeout: float = 300.0):
|
def __init__(self, dropdown_objects: list[discord.ui.Select], timeout: float = 300.0):
|
||||||
super().__init__(timeout=timeout)
|
super().__init__(timeout=timeout)
|
||||||
|
|
||||||
# self.add_item(Dropdown())
|
# self.add_item(Dropdown())
|
||||||
for x in dropdown_objects:
|
for x in dropdown_objects:
|
||||||
self.add_item(x)
|
self.add_item(x)
|
||||||
|
|
||||||
|
|
||||||
|
class SelectViewDefense(discord.ui.Select):
|
||||||
|
def __init__(self, options: list, this_play: Play, base_embed: discord.Embed, session: Session, sorted_lineups: list[Lineup]):
|
||||||
|
self.embed = base_embed
|
||||||
|
self.session = session
|
||||||
|
self.play = this_play
|
||||||
|
self.sorted_lineups = sorted_lineups
|
||||||
|
super().__init__(options=options)
|
||||||
|
|
||||||
|
async def callback(self, interaction: discord.Interaction):
|
||||||
|
logging.info(f'SelectViewDefense - selection: {self.values[0]}')
|
||||||
|
|
||||||
|
this_lineup = self.session.get(Lineup, self.values[0])
|
||||||
|
self.embed.set_image(url=this_lineup.player.image)
|
||||||
|
|
||||||
|
select_player_options = [
|
||||||
|
discord.SelectOption(label=f'{x.position} - {x.player.name}', value=f'{x.id}', default=this_lineup.position == x.position) for x in self.sorted_lineups
|
||||||
|
]
|
||||||
|
player_dropdown = SelectViewDefense(
|
||||||
|
options=select_player_options,
|
||||||
|
this_play=self.play,
|
||||||
|
base_embed=self.embed,
|
||||||
|
session=self.session,
|
||||||
|
sorted_lineups=self.sorted_lineups
|
||||||
|
)
|
||||||
|
new_view = DropdownView(
|
||||||
|
dropdown_objects=[player_dropdown],
|
||||||
|
timeout=60
|
||||||
|
)
|
||||||
|
|
||||||
|
await interaction.response.edit_message(content=None, embed=self.embed, view=new_view)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SelectOpenPack(discord.ui.Select):
|
||||||
|
def __init__(self, options: list, team: dict):
|
||||||
|
self.owner_team = team
|
||||||
|
super().__init__(placeholder='Select a Pack Type', options=options)
|
||||||
|
|
||||||
|
async def callback(self, interaction: discord.Interaction):
|
||||||
|
logging.info(f'SelectPackChoice - selection: {self.values[0]}')
|
||||||
|
pack_vals = self.values[0].split('-')
|
||||||
|
logging.info(f'pack_vals: {pack_vals}')
|
||||||
|
|
||||||
|
# Get the selected packs
|
||||||
|
params = [('team_id', self.owner_team['id']), ('opened', False), ('limit', 5), ('exact_match', True)]
|
||||||
|
|
||||||
|
open_type = 'standard'
|
||||||
|
if 'Standard' in pack_vals:
|
||||||
|
open_type = 'standard'
|
||||||
|
params.append(('pack_type_id', 1))
|
||||||
|
elif 'Premium' in pack_vals:
|
||||||
|
open_type = 'standard'
|
||||||
|
params.append(('pack_type_id', 3))
|
||||||
|
elif 'Daily' in pack_vals:
|
||||||
|
params.append(('pack_type_id', 4))
|
||||||
|
elif 'Promo Choice' in pack_vals:
|
||||||
|
open_type = 'choice'
|
||||||
|
params.append(('pack_type_id', 9))
|
||||||
|
elif 'MVP' in pack_vals:
|
||||||
|
open_type = 'choice'
|
||||||
|
params.append(('pack_type_id', 5))
|
||||||
|
elif 'All Star' in pack_vals:
|
||||||
|
open_type = 'choice'
|
||||||
|
params.append(('pack_type_id', 6))
|
||||||
|
elif 'Mario' in pack_vals:
|
||||||
|
open_type = 'choice'
|
||||||
|
params.append(('pack_type_id', 7))
|
||||||
|
elif 'Team Choice' in pack_vals:
|
||||||
|
open_type = 'choice'
|
||||||
|
params.append(('pack_type_id', 8))
|
||||||
|
else:
|
||||||
|
raise KeyError(f'Cannot identify pack details: {pack_vals}')
|
||||||
|
|
||||||
|
# If team isn't already set on team choice pack, make team pack selection now
|
||||||
|
await interaction.response.edit_message(view=None)
|
||||||
|
|
||||||
|
cardset_id = None
|
||||||
|
if 'Team Choice' in pack_vals and 'Cardset' in pack_vals:
|
||||||
|
# cardset_id = pack_vals[2]
|
||||||
|
cardset_index = pack_vals.index('Cardset')
|
||||||
|
cardset_id = pack_vals[cardset_index + 1]
|
||||||
|
params.append(('pack_cardset_id', cardset_id))
|
||||||
|
if 'Team' not in pack_vals:
|
||||||
|
view = SelectView(
|
||||||
|
[SelectChoicePackTeam('AL', self.owner_team, cardset_id),
|
||||||
|
SelectChoicePackTeam('NL', self.owner_team, cardset_id)],
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
await interaction.channel.send(
|
||||||
|
content=None,
|
||||||
|
view=view
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
params.append(('pack_team_id', pack_vals[pack_vals.index('Team') + 1]))
|
||||||
|
else:
|
||||||
|
if 'Team' in pack_vals:
|
||||||
|
params.append(('pack_team_id', pack_vals[pack_vals.index('Team') + 1]))
|
||||||
|
if 'Cardset' in pack_vals:
|
||||||
|
cardset_id = pack_vals[pack_vals.index('Cardset') + 1]
|
||||||
|
params.append(('pack_cardset_id', cardset_id))
|
||||||
|
|
||||||
|
p_query = await db_get('packs', params=params)
|
||||||
|
if p_query['count'] == 0:
|
||||||
|
logging.error(f'open-packs - no packs found with params: {params}')
|
||||||
|
raise ValueError(f'Unable to open packs')
|
||||||
|
|
||||||
|
# Open the packs
|
||||||
|
if open_type == 'standard':
|
||||||
|
await open_st_pr_packs(p_query['packs'], self.owner_team, interaction)
|
||||||
|
elif open_type == 'choice':
|
||||||
|
await open_choice_pack(p_query['packs'][0], self.owner_team, interaction, cardset_id)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user