from typing import List import discord import logging from discord import SelectOption from discord.utils import MISSING from sqlmodel import Session from exceptions import CardNotFoundException, log_exception from in_game.game_helpers import legal_check from in_game.gameplay_models import Game, Lineup, Play, Team from in_game.gameplay_queries import get_position, get_card_or_none logger = logging.getLogger('discord_app') 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): # Set the options that will be presented inside the dropdown # options = [ # discord.SelectOption(label='Red', description='Your favourite colour is red', emoji='🟥'), # discord.SelectOption(label='Green', description='Your favourite colour is green', emoji='🟩'), # discord.SelectOption(label='Blue', description='Your favourite colour is blue', emoji='🟦'), # ] # The placeholder is what will be shown when no option is chosen # The min and max values indicate we can only pick one of the three options # The options parameter defines the dropdown options. We defined this above # If a default option is set on any SelectOption, the View will not process if only the default is # selected by the user self.custom_callback = callback super().__init__( placeholder=placeholder, min_values=min_values, max_values=max_values, options=option_list ) async def callback(self, interaction: discord.Interaction): # Use the interaction object to send a response message containing # the user's favourite colour or choice. The self object refers to the # Select object, and the values attribute gets a list of the user's # selected options. We only want the first one. # await interaction.response.send_message(f'Your favourite colour is {self.values[0]}') logger.info(f'Dropdown callback: {self.custom_callback}') await self.custom_callback(interaction, self.values) class DropdownView(discord.ui.View): """ https://discordpy.readthedocs.io/en/latest/interactions/api.html#select """ def __init__(self, dropdown_objects: list[discord.ui.Select], timeout: float = 300.0): super().__init__(timeout=timeout) # self.add_item(Dropdown()) for x in dropdown_objects: 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): logger.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 SelectStartingPitcher(discord.ui.Select): def __init__(self, this_game: Game, this_team: Team, session: Session, league_name: str, custom_id: str = MISSING, placeholder: str | None = None, options: List[SelectOption] = ...) -> None: logger.info(f'Inside SelectStartingPitcher init function') self.game = this_game self.team = this_team self.session = session self.league_name = league_name super().__init__(custom_id=custom_id, placeholder=placeholder, options=options) async def callback(self, interaction: discord.Interaction): logger.info(f'SelectStartingPitcher - selection: {self.values[0]}') # Get Human SP card human_sp_card = await get_card_or_none(self.session, card_id=self.values[0]) if human_sp_card is None: log_exception(CardNotFoundException, f'Card ID {self.values[0]} not found') if human_sp_card.team_id != self.team.id: logger.error(f'Card_id {self.values[0]} does not belong to {self.team.abbrev} in Game {self.game.id}') await interaction.channel.send( f'Uh oh. Card ID {self.values[0]} is {human_sp_card.player.name} and belongs to {human_sp_card.team.sname}. Will you double check that before we get started?' ) return await get_position(self.session, human_sp_card, 'P') legal_data = await legal_check([self.values[0]], difficulty_name=self.league_name) if not legal_data['legal']: await interaction.edit_original_response( content=f'It looks like this is a Ranked Legal game and {human_sp_card.player.name_with_desc} is not legal in {self.league_name} games. You can start a new game once you pick a new SP.' ) return human_sp_lineup = Lineup( team_id=self.team.id, player_id=human_sp_card.player.id, card_id=self.values[0], position='P', batting_order=10, is_fatigued=False, game=self.game ) self.session.add(human_sp_lineup) self.session.commit() await interaction.response.edit_message( content=f'The {self.team.lname} are starting {human_sp_card.player.name_with_desc}', view=None )