From a4af7652fc14fb851efa6cb370e586f511b9586c Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Thu, 21 Nov 2024 10:38:39 -0600 Subject: [PATCH] ask_confirm bug fix manual_end_game complete --- cogs/gameplay.py | 11 +++- command_logic/logic_gameplay.py | 101 +++++++++++++++++++++++++++++++- exceptions.py | 8 +++ in_game/gameplay_models.py | 15 ++++- utilities/buttons.py | 10 ++-- 5 files changed, 135 insertions(+), 10 deletions(-) diff --git a/cogs/gameplay.py b/cogs/gameplay.py index bdce540..2d42c87 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -8,7 +8,7 @@ from discord.ext import commands, tasks import pygsheets from api_calls import db_get -from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, popouts, show_defense_cards, singles, strikeouts, triples, undo_play, update_game_settings, walks +from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, manual_end_game, popouts, show_defense_cards, singles, strikeouts, triples, undo_play, update_game_settings, walks from dice import ab_roll from exceptions import GameNotFoundException, TeamNotFoundException, PlayNotFoundException, GameException, log_exception from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, get_channel, team_role, user_has_role, random_gif, random_from_list @@ -448,6 +448,15 @@ class Gameplay(commands.Cog): auto_roll=auto_roll )) + @app_commands.command(name='end-game', description='End the current game in this channel') + @app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME) + async def end_game_command(self, interaction: discord.Interaction): + with Session(engine) as session: + this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='end-game') + + # await interaction.edit_original_response(content='Let\'s see, I didn\'t think this game was over...') + await manual_end_game(session, interaction, this_game, current_play=this_play) + group_log = app_commands.Group(name='log', description='Log a play in this channel\'s game') @group_log.command(name='flyball', description='Flyballs: a, b, ballpark, bq, c') diff --git a/command_logic/logic_gameplay.py b/command_logic/logic_gameplay.py index a40dc8b..d1733f0 100644 --- a/command_logic/logic_gameplay.py +++ b/command_logic/logic_gameplay.py @@ -14,7 +14,7 @@ from in_game.game_helpers import legal_check from in_game.gameplay_models import BattingCard, Game, Lineup, PositionRating, Team, Play from in_game.gameplay_queries import get_and_cache_position, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_last_team_play, get_one_lineup, get_player_id_from_dict, get_player_name_from_dict, get_player_or_none, get_sorted_lineups, get_team_or_none, get_players_last_pa, post_game_rewards from utilities.buttons import ButtonOptions, Confirm, ask_confirm -from utilities.dropdown import DropdownOptions, DropdownView, SelectViewDefense +from utilities.dropdown import DropdownView, SelectViewDefense from utilities.embeds import image_embed from utilities.pages import Pagination @@ -1618,7 +1618,7 @@ async def get_game_summary_embed(session: Session, interaction: discord.Interact if len(poop_string) > 0: game_embed.add_field( - 'Pooper of the Game', + name='Pooper of the Game', value=poop_string, inline=False ) @@ -1855,3 +1855,100 @@ async def update_game_settings(session: Session, interaction: discord.Interactio ) return embed + + +async def manual_end_game(session: Session, interaction: discord.Interaction, this_game: Game, current_play: Play): + logger.info(f'manual_end_game - Game {this_game.id}') + GAME_DONE_STRING = 'Okay, it\'s gone. You\'re free to start another one!' + GAME_STAYS_STRING = 'No problem, this game will continue!' + + if not is_game_over(current_play): + logger.info(f'manual_end_game - game is not over') + + if current_play.inning_num == 1 and current_play.play_num < 3 and 'gauntlet' not in this_game.game_type.lower(): + logger.info(f'manual_end_game - {this_game.game_type} game just started, asking for confirmation') + + await interaction.edit_original_response(content='Looks like this game just started.') + + cancel_early = await ask_confirm( + interaction, + 'Are you sure you want to cancel it?', + label_type='yes', + timeout=30, + delete_question=False + ) + + if cancel_early: + logger.info(f'{interaction.user.name} is cancelling the game') + await interaction.channel.send(content=GAME_DONE_STRING) + + news_ticker = get_channel(interaction, 'pd-network-news') + if news_ticker is not None: + await news_ticker.send(content=f'{interaction.user.display_name} had dinner plans so had to end their game down in {interaction.channel.mention} early.') + + this_game.active = False + session.add(this_game) + session.commit() + + else: + logger.info(f'{interaction.user.name} is not cancelling the game') + await interaction.channel.send_message(content=GAME_STAYS_STRING) + + return + + else: + logger.info(f'manual_end_game - {this_game.game_type} game currently in inning #{current_play.inning_num}, asking for confirmation') + + await interaction.edit_original_response(content='It doesn\'t look like this game isn\'t over, yet. I can end it, but no rewards will be paid out and you will take the L.') + + forfeit_game = await ask_confirm( + interaction, + 'Should I end this game?', + label_type='yes', + timeout=30, + delete_question=False + ) + + if forfeit_game: + logger.info(f'{interaction.user.name} is forfeiting the game') + game_data = this_game.model_dump() + game_data['home_team_ranking'] = this_game.home_team.ranking + game_data['away_team_ranking'] = this_game.away_team.ranking + game_data['home_team_value'] = this_game.home_team.team_value + game_data['away_team_value'] = this_game.away_team.team_value + game_data['away_score'] = current_play.away_score + game_data['home_score'] = current_play.home_score + game_data['forfeit'] = True + + try: + db_game = await db_post('games', payload=game_data) + except Exception as e: + logger.error(f'Unable to post forfeited game') + + await interaction.channel.send(content=GAME_DONE_STRING) + + news_ticker = get_channel(interaction, 'pd-network-news') + if news_ticker is not None: + await news_ticker.send(content=f'{interaction.user.display_name} escorts the {this_game.human_team.sname} out of {interaction.channel.mention} in protest.') + + this_game.active = False + session.add(this_game) + session.commit() + + else: + logger.info(f'{interaction.user.name} is not forfeiting the game') + await interaction.channel.send(content=GAME_STAYS_STRING) + + return + + # else: + # logger.info(f'manual_end_game - gauntlet game currently in inning #{current_play.inning_num}, asking for confirmation') + + # await interaction.edit_original_response(content='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.') + + else: + logger.info(f'manual_end_game - game is over') + await complete_game(session, interaction, current_play) + + + diff --git a/exceptions.py b/exceptions.py index 4859ddc..845a886 100644 --- a/exceptions.py +++ b/exceptions.py @@ -57,3 +57,11 @@ class PositionNotFoundException(GameException): class NoPlayerResponseException(GameException): pass + + +class MultipleHumanTeamsException(GameException): + pass + + +class NoHumanTeamsException(GameException): + pass diff --git a/in_game/gameplay_models.py b/in_game/gameplay_models.py index f4e2f1d..29a59c8 100644 --- a/in_game/gameplay_models.py +++ b/in_game/gameplay_models.py @@ -106,8 +106,8 @@ class Game(SQLModel, table=True): first_message: str | None = Field(default=None) ai_team: str | None = Field(default=None) game_type: str - roll_buttons: bool | None = Field(default=False) - auto_roll: bool | None = Field(default=True) + roll_buttons: bool | None = Field(default=True) + auto_roll: bool | None = Field(default=False) cardset_links: list[GameCardsetLink] = Relationship(back_populates='game', cascade_delete=True) away_team: Team = Relationship( @@ -409,6 +409,17 @@ class Game(SQLModel, table=True): return lineup_val + @property + def human_team(self): + if self.home_team.is_ai and not self.away_team.is_ai: + return self.away_team + elif self.away_team.is_ai and not self.home_team.is_ai: + return self.home_team + elif self.home_team.is_ai and self.away_team.is_ai: + raise NoHumanTeamsException + else: + raise MultipleHumanTeamsException + class ManagerAi(ManagerAiBase, table=True): plays: list['Play'] = Relationship(back_populates='managerai') diff --git a/utilities/buttons.py b/utilities/buttons.py index e566e14..46c20c8 100644 --- a/utilities/buttons.py +++ b/utilities/buttons.py @@ -159,21 +159,21 @@ async def ask_confirm(interaction: discord.Interaction, question: str, label_typ if custom_cancel_label: view.cancel.label = custom_cancel_label - question = await interaction.channel.send(question, view=view) + q_message = await interaction.channel.send(question, view=view) await view.wait() if view.value: if delete_question: - await question.delete() + await q_message.delete() else: - await question.edit(content=question, view=None) + await q_message.edit(content=question, view=None) return True else: if delete_question: - await question.delete() + await q_message.delete() else: - await question.edit(content=question, view=None) + await q_message.edit(content=question, view=None) return False