import logging import discord from typing import Coroutine, Literal from dice import ab_roll, jump_roll from in_game.gameplay_models import Game, Play, Team logger = logging.getLogger('discord_app') class Confirm(discord.ui.View): def __init__(self, responders: list, timeout: float = 300.0, label_type: Literal['yes', 'confirm'] = 'confirm'): super().__init__(timeout=timeout) if not isinstance(responders, list): raise TypeError('responders must be a list') self.value = None self.responders = responders if label_type == 'yes': self.confirm.label = 'Yes' self.cancel.label = 'No' # When the confirm button is pressed, set the inner value to `True` and # stop the View from listening to more input. # We also send the user an ephemeral message that we're confirming their choice. @discord.ui.button(label='Confirm', style=discord.ButtonStyle.green) async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = True self.clear_items() self.stop() # This one is similar to the confirmation button except sets the inner value to `False` @discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey) async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = False self.clear_items() self.stop() class ButtonOptions(discord.ui.View): def __init__(self, responders: list, timeout: float = 300.0, labels=None): super().__init__(timeout=timeout) if not isinstance(responders, list): raise TypeError('responders must be a list') self.value = None self.responders = responders self.options = labels for count, x in enumerate(labels): if count == 0: self.option1.label = x if x is None or x.lower() == 'na' or x == 'N/A': self.remove_item(self.option1) if count == 1: self.option2.label = x if x is None or x.lower() == 'na' or x == 'N/A': self.remove_item(self.option2) if count == 2: self.option3.label = x if x is None or x.lower() == 'na' or x == 'N/A': self.remove_item(self.option3) if count == 3: self.option4.label = x if x is None or x.lower() == 'na' or x == 'N/A': self.remove_item(self.option4) if count == 4: self.option5.label = x if x is None or x.lower() == 'na' or x == 'N/A': self.remove_item(self.option5) @discord.ui.button(label='Option 1', style=discord.ButtonStyle.primary) async def option1(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = self.options[0] self.clear_items() self.stop() @discord.ui.button(label='Option 2', style=discord.ButtonStyle.primary) async def option2(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = self.options[1] self.clear_items() self.stop() @discord.ui.button(label='Option 3', style=discord.ButtonStyle.primary) async def option3(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = self.options[2] self.clear_items() self.stop() @discord.ui.button(label='Option 4', style=discord.ButtonStyle.primary) async def option4(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = self.options[3] self.clear_items() self.stop() @discord.ui.button(label='Option 5', style=discord.ButtonStyle.primary) async def option5(self, interaction: discord.Interaction, button: discord.ui.Button): if interaction.user not in self.responders: await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=10.0 ) self.value = self.options[4] self.clear_items() self.stop() async def ask_confirm(interaction: discord.Interaction, question: str, label_type: Literal['yes', 'confirm'] = 'confirm', timeout: int = 60, delete_question: bool = True, custom_confirm_label: str = None, custom_cancel_label: str = None, embed: discord.Embed = None, delete_embed: bool = False) -> bool: """ button_callbacks: keys are button values, values are async functions """ try: view = Confirm(responders=[interaction.user], timeout=timeout, label_type=label_type) except AttributeError: view = Confirm(responders=[interaction.author], timeout=timeout, label_type=label_type) if custom_confirm_label: view.confirm.label = custom_confirm_label if custom_cancel_label: view.cancel.label = custom_cancel_label q_message = await interaction.channel.send(question, view=view) await view.wait() if view.value: if delete_question: await q_message.delete() else: await q_message.edit(content=question, view=None) return True else: if delete_question: await q_message.delete() else: await q_message.edit(content=question, view=None) return False class ScorebugButtons(discord.ui.View): def __init__(self, play: Play, embed: discord.Embed, timeout: float = 30): super().__init__(timeout=timeout) self.value = None self.batting_team = play.batter.team self.pitching_team = play.pitcher.team self.pitcher_card_url = play.pitcher.player.pitcher_card_url self.batter_card_url = play.batter.player.batter_card_url self.team = play.batter.team self.play = play self.had_chaos = False self.embed = embed if play.on_base_code == 0: self.remove_item(self.button_jump) async def interaction_check(self, interaction: discord.Interaction[discord.Client]) -> bool: logger.info(f'user id: {interaction.user.id} / batting_team: {self.batting_team}') if interaction.user.id == self.batting_team.gmid: logger.info(f'User {interaction.user.id} rolling in Game {self.play.game.id}') return True elif self.batting_team.is_ai and interaction.user.id == self.pitching_team.gmid: logger.info(f'User {interaction.user.id} rolling for AI in Game {self.play.game.id}') return True logger.info(f'User {interaction.user.id} rejected in Game {self.play.game.id}') await interaction.response.send_message( content='Get out of here', ephemeral=True, delete_after=5.0 ) return False # async def on_timeout(self) -> Coroutine[Any, Any, None]: # await self.interaction @discord.ui.button(label='Roll AB', style=discord.ButtonStyle.primary) async def button_ab(self, interaction: discord.Interaction, button: discord.ui.Button): logger.info(f'User {interaction.user.id} rolling AB in Game {self.play.game.id}') this_roll = ab_roll(self.team, self.play.game, allow_chaos=not self.had_chaos) logger.info(f'this_roll: {this_roll}') if this_roll.is_chaos: logger.info('AB Roll Is Chaos') self.had_chaos = True else: button.disabled = True await interaction.channel.send(content=None, embeds=this_roll.embeds) if this_roll.d_six_one > 3: logger.info(f'ScorebugButton - updating embed card to pitcher') self.embed.set_image(url=self.pitcher_card_url) logger.debug(f'embed image url: {self.embed.image}') logger.debug(f'new embed: {self.embed}') await interaction.response.edit_message(view=self, embed=self.embed) @discord.ui.button(label='Check Jump', style=discord.ButtonStyle.secondary) async def button_jump(self, interaction: discord.Interaction, button: discord.ui.Button): logger.info(f'User {interaction.user.id} rolling jump in Game {self.play.game.id}') this_roll = jump_roll(self.team, self.play.game) button.disabled = True await interaction.channel.send(content=None, embeds=this_roll.embeds) await interaction.response.edit_message(view=self)