paper-dynasty-discord/helpers.py
Cal Corum 965ceebd35 Add responders check to dropdowns
Add colors and insults to helpers
Finish /set commands with helpers post /new-game
Add POW check for pitchers
2024-12-27 22:33:25 -06:00

3374 lines
139 KiB
Python

import asyncio
import datetime
import logging
import math
import os
import random
import traceback
import discord
import pygsheets
import requests
from discord.ext import commands
from api_calls import *
from bs4 import BeautifulSoup
from difflib import get_close_matches
from dataclasses import dataclass
from typing import Optional, Literal
from in_game.gameplay_models import Team
SBA_SEASON = 10
PD_SEASON = 8
LIVE_CARDSET_ID = 20
LIVE_PROMO_CARDSET_ID = 21
SBA_COLOR = 'a6ce39'
PD_PLAYERS = 'Paper Dynasty Players'
SBA_PLAYERS_ROLE_NAME = f'Season {SBA_SEASON} Players'
PD_PLAYERS_ROLE_NAME = f'Paper Dynasty Players'
PD_CARD_URL = 'https://sombaseball.ddns.net/cards/pd'
PKMN_REF_URL = 'https://pkmncards.com/card/'
RATINGS_BATTER_FORMULA = '=IMPORTRANGE("1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE","guide_Batters!A1:CD")'
RATINGS_PITCHER_FORMULA = '=IMPORTRANGE("1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE","guide_Pitchers!A1:BQ")'
RATINGS_SHEET_KEY = '1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE'
ALL_MLB_TEAMS = {
'Arizona Diamondbacks': ['ARI', 'Diamondbacks'],
'Atlanta Braves': ['ATL', 'MLN', 'Braves'],
'Baltimore Orioles': ['BAL', 'Orioles'],
'Boston Red Sox': ['BOS', 'Red Sox'],
'Chicago Cubs': ['CHC', 'Cubs'],
'Chicago White Sox': ['CHW', 'White Sox'],
'Cincinnati Reds': ['CIN', 'Reds'],
'Cleveland Guardians': ['CLE', 'Guardians'],
'Colorado Rockies': ['COL', 'Rockies'],
'Detroit Tigers': ['DET', 'Tigers'],
'Houston Astros': ['HOU', 'Astros'],
'Kansas City Royals': ['KCR', 'Royals'],
'Los Angeles Angels': ['LAA', 'CAL', 'Angels'],
'Los Angeles Dodgers': ['LAD', 'Dodgers'],
'Miami Marlins': ['MIA', 'Marlins'],
'Milwaukee Brewers': ['MIL', 'MKE', 'Brewers'],
'Minnesota Twins': ['MIN', 'Twins'],
'New York Mets': ['NYM', 'Mets'],
'New York Yankees': ['NYY', 'Yankees'],
'Oakland Athletics': ['OAK', 'Athletics'],
'Philadelphia Phillies': ['PHI', 'Phillies'],
'Pittsburgh Pirates': ['PIT', 'Pirates'],
'San Diego Padres': ['SDP', 'Padres'],
'Seattle Mariners': ['SEA', 'Mariners'],
'San Francisco Giants': ['SFG', 'Giants'],
'St Louis Cardinals': ['STL', 'Cardinals'],
'Tampa Bay Rays': ['TBR', 'Rays'],
'Texas Rangers': ['TEX', 'Senators', 'Rangers'],
'Toronto Blue Jays': ['TOR', 'Jays'],
'Washington Nationals': ['WSN', 'WAS', 'Nationals'],
}
IMAGES = {
'logo': 'https://sombaseball.ddns.net/static/images/sba-logo.png',
'mvp-hype': f'{PD_CARD_URL}/mvp.png',
'pack-sta': f'{PD_CARD_URL}/pack-standard.png',
'pack-pre': f'{PD_CARD_URL}/pack-premium.png',
'pack-mar': f'{PD_CARD_URL}/sluggers/mario-gauntlet.png',
'pack-pkmnbs': f'https://i.postimg.cc/635M4X52/pokemon-brilliantstars.jpg',
'mvp': {
'Arizona Diamondbacks': f'{PD_CARD_URL}/mvp/arizona-diamondbacks.gif',
'Atlanta Braves': f'{PD_CARD_URL}/mvp/atlanta-braves.gif',
'Baltimore Orioles': f'{PD_CARD_URL}/mvp/baltimore-orioles.gif',
'Boston Red Sox': f'{PD_CARD_URL}/mvp/boston-red-sox.gif',
'Chicago Cubs': f'{PD_CARD_URL}/mvp/chicago-cubs.gif',
'Chicago White Sox': f'{PD_CARD_URL}/mvp/chicago-white-sox.gif',
'Cincinnati Reds': f'{PD_CARD_URL}/mvp/cincinnati-reds.gif',
'Cleveland Indians': f'{PD_CARD_URL}/mvp/cleveland-guardians.gif',
'Cleveland Guardians': f'{PD_CARD_URL}/mvp/cleveland-guardians.gif',
'Colorado Rockies': f'{PD_CARD_URL}/mvp/colorado-rockies.gif',
'Detroit Tigers': f'{PD_CARD_URL}/mvp/detroit-tigers.gif',
'Houston Astros': f'{PD_CARD_URL}/mvp/houston-astros.gif',
'Kansas City Royals': f'{PD_CARD_URL}/mvp/kansas-city-royals.gif',
'Los Angeles Angels': f'{PD_CARD_URL}/mvp/los-angeles-angels.gif',
'Los Angeles Dodgers': f'{PD_CARD_URL}/mvp/los-angeles-dodgers.gif',
'Miami Marlins': f'{PD_CARD_URL}/mvp/miami-marlins.gif',
'Milwaukee Brewers': f'{PD_CARD_URL}/mvp/milwaukee-brewers.gif',
'Minnesota Twins': f'{PD_CARD_URL}/mvp/minnesota-twins.gif',
'New York Mets': f'{PD_CARD_URL}/mvp/new-york-mets.gif',
'New York Yankees': f'{PD_CARD_URL}/mvp/new-york-yankees.gif',
'Oakland Athletics': f'{PD_CARD_URL}/mvp/oakland-athletics.gif',
'Philadelphia Phillies': f'{PD_CARD_URL}/mvp/philadelphia-phillies.gif',
'Pittsburgh Pirates': f'{PD_CARD_URL}/mvp/pittsburgh-pirates.gif',
'San Diego Padres': f'{PD_CARD_URL}/mvp/san-diego-padres.gif',
'Seattle Mariners': f'{PD_CARD_URL}/mvp/seattle-mariners.gif',
'San Francisco Giants': f'{PD_CARD_URL}/mvp/san-francisco-giants.gif',
'St Louis Cardinals': f'{PD_CARD_URL}/mvp/st-louis-cardinals.gif',
'St. Louis Cardinals': f'{PD_CARD_URL}/mvp/st-louis-cardinals.gif',
'Tampa Bay Rays': f'{PD_CARD_URL}/mvp/tampa-bay-rays.gif',
'Texas Rangers': f'{PD_CARD_URL}/mvp/texas-rangers.gif',
'Toronto Blue Jays': f'{PD_CARD_URL}/mvp/toronto-blue-jays.gif',
'Washington Nationals': f'{PD_CARD_URL}/mvp/washington-nationals.gif',
'Junior All Stars': f'{PD_CARD_URL}/mvp.png',
'Mario Super Sluggers': f'{PD_CARD_URL}/mvp.png',
'Pokemon League': 'https://i.postimg.cc/ydzYB7BR/masterball.jpg'
},
'gauntlets': f'{PD_CARD_URL}/gauntlets.png'
}
INFIELD_X_CHART = {
'si1': {
'rp': 'No runner on first: Batter is safe at first and no one covers second. Batter to second, runners only '
'advance 1 base.\nRunner on first: batter singles, runners advance 1 base.',
'e1': 'Single and Error, batter to second, runners advance 2 bases.',
'e2': 'Single and Error, batter to third, all runners score.',
'no': 'Single, runners advance 1 base.'
},
'po': {
'rp': 'The batters hits a popup. None of the fielders take charge on the play and the ball drops in the '
'infield for a SI1! All runners advance 1 base.',
'e1': 'The catcher drops a popup for an error. All runners advance 1 base.',
'e2': 'The catcher grabs a squib in front of the plate and throws it into right field. The batter goes to '
'second and all runners score.',
'no': 'The batter pops out to the catcher.'
},
'fo': {
'rp': 'Batter swings and misses, but is awarded first base on a catcher interference call! One base error, '
'baserunners advance only if forced.',
'e1': 'The catcher drops a foul popup for an error. Batter rolls AB again.',
'e2': 'The catcher drops a foul popup for an error. Batter rolls AB again.',
'no': 'Runner(s) on base: make a passed ball check. If no passed ball, batter pops out to the catcher. If a '
'passed ball occurs, batter roll his AB again.\nNo runners: batter pops out to the catcher'
},
'g1': {
'rp': 'Runner on first, <2 outs: runner on first breaks up the double play, gbB\n'
'Else: gbA',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbA`'
},
'g2': {
'rp': 'Runner(s) on base: fielder makes bad throw for lead runner but batter is out at first for a gbC\n'
'No runners: gbB',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbB`'
},
'g3': {
'rp': 'Runner(s) on base: fielder checks the runner before throwing to first and allows a SI*\n'
'No runners: gbC',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbC`'
},
'spd': {
'rp': 'Catcher throws to first and hits the batter-runner in the back, SI1',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Speed check, Batter\'s safe range = Running; if safe, SI*; if out, gbC'
},
}
OUTFIELD_X_CHART = {
'si2': {
'rp': 'Batter singles, baserunners advance 2 bases. As the batter rounds first, the fielder throws behind him '
'and catches him off the bag for an out!',
'e1': 'Single and error, batter to second, runners advance 2 bases.',
'e2': 'Single and error, batter to third, all runners score.',
'e3': 'Single and error, batter to third, all runners score',
'no': 'Single, all runners advance 2 bases.'
},
'do2': {
'rp': 'Batter doubles and runners advance three bases, but batter-runner is caught between second and third! '
'He is tagged out in the rundown.',
'e1': 'Double and error, batter to third, all runners score.',
'e2': 'Double and error, batter to third, all runners score.',
'e3': 'Double and error, batter and all runners score. Little league home run!',
'no': 'Double, all runners advance 2 bases.'
},
'do3': {
'rp': 'Batter doubles and runners advance three bases, but batter-runner is caught between second and third! '
'He is tagged out in the rundown.',
'e1': 'Double and error, batter to third, all runners score.',
'e2': 'Double and error, batter and all runners score. Little league home run!',
'e3': 'Double and error, batter and all runners score. Little league home run!',
'no': 'Double, all runners score.'
},
'tr3': {
'rp': 'Batter hits a ball into the gap and the outfielders collide trying to make the play! The ball rolls to '
'the wall and the batter trots home with an inside-the-park home run!',
'e1': 'Triple and error, batter and all runners score. Little league home run!',
'e2': 'Triple and error, batter and all runners score. Little league home run!',
'e3': 'Triple and error, batter and all runners score. Little league home run!',
'no': 'Triple, all runners score.'
},
'f1': {
'rp': 'The outfielder races back and makes a diving catch and collides with the wall! In the time he takes to '
'recuperate, all baserunners tag-up and advance 2 bases.',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball A'
},
'f2': {
'rp': 'The outfielder catches the flyball for an out. If there is a runner on third, he tags-up and scores. '
'The play is appealed and the umps rule that the runner left early and is out on the appeal!',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball B'
},
'f3': {
'rp': 'The outfielder makes a running catch in the gap! The lead runner lost track of the ball and was '
'advancing - he cannot return in time and is doubled off by the outfielder.',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball C'
}
}
RARITY = {
'HoF': 8,
'MVP': 5,
'All-Star': 3,
'Starter': 2,
'Reserve': 1,
'Replacement': 0
}
SELECT_CARDSET_OPTIONS = [
discord.SelectOption(label='1998 Live', value='20'),
discord.SelectOption(label='1998 Promos', value='21'),
discord.SelectOption(label='2024 Season', value='17'),
discord.SelectOption(label='2024 Promos', value='18'),
discord.SelectOption(label='2023 Season', value='9'),
discord.SelectOption(label='2023 Promos', value='10'),
discord.SelectOption(label='2022 Season', value='3'),
discord.SelectOption(label='2022 Promos', value='4'),
discord.SelectOption(label='2021 Season', value='1'),
discord.SelectOption(label='2019 Season', value='5'),
discord.SelectOption(label='2018 Season', value='13'),
discord.SelectOption(label='2018 Promos', value='14'),
discord.SelectOption(label='2016 Season', value='11'),
discord.SelectOption(label='2013 Season', value='6'),
discord.SelectOption(label='2012 Season', value='7')
]
ACTIVE_EVENT_LITERAL = Literal['1998 Season']
DEFENSE_LITERAL = Literal['Pitcher', 'Catcher', 'First Base', 'Second Base', 'Third Base', 'Shortstop', 'Left Field', 'Center Field', 'Right Field']
ACTIVE_EVENT_LITERAL = Literal['1998 Season', 'Brilliant Stars']
COLORS = {
'sba': int('a6ce39', 16),
'yellow': int('FFEA00', 16),
'red': int('C70039', 16)
}
INSULTS = [
'Ugh, who even are you?',
'Ugh, who even are you? Go away.',
'Ugh, who even are you? Leave me alone.',
'I will call the fucking cops!',
'I will call the fucking cops! Go away.',
'I will call the fucking cops! Leave me alone',
'Please don\'t talk to me',
'Don\'t talk to me.',
'Eww, don\'t talk to me.',
'Get away from me.',
'Get away from me, creep.',
'Get away from me, loser.',
'Get away from me, pedobear.',
'Why are you even here?',
'Why are you even here? Get lost.',
'Why are you even here? Scram.',
'Why are you even here? No one knows who you are.',
]
class Question:
def __init__(self, bot, channel, prompt, qtype, timeout, embed=None):
"""
Version 0.4
:param bot, discord bot object
:param channel, discord Channel object
:param prompt, string, prompt message to post
:param qtype, string, 'yesno', 'int', 'float', 'text', or 'url'
:param timeout, float, time to wait for a response
"""
if not prompt and not embed:
raise TypeError('prompt and embed may not both be None')
self.bot = bot
self.channel = channel
self.prompt = prompt
self.qtype = qtype
self.timeout = timeout
self.embed = embed
async def ask(self, responders: list):
"""
Params: responder, list of discord User objects
Returns: True/False if confirm question; full response otherwise
"""
yes = ['yes', 'y', 'ye', 'yee', 'yerp', 'yep', 'yeet', 'yip', 'yup', 'yarp', 'si']
no = ['no', 'n', 'nope', 'nah', 'nyet', 'nein']
if type(responders) is not list:
raise TypeError('Responders must be a list of Members')
def yesno(mes):
return mes.channel == self.channel and mes.author in responders and mes.content.lower() in yes + no
def text(mes):
return mes.channel == self.channel and mes.author in responders
await self.channel.send(content=self.prompt, embed=self.embed)
try:
resp = await self.bot.wait_for(
'message',
timeout=self.timeout,
check=yesno if self.qtype == 'yesno' else text
)
except asyncio.TimeoutError:
return None
except Exception as e:
await self.channel.send(f'Yuck, do you know what this means?\n\n{e}')
return None
if self.qtype == 'yesno':
if resp.content.lower() in yes:
return True
else:
return False
elif self.qtype == 'int':
return int(resp.content)
elif self.qtype == 'float':
return float(resp.content)
elif self.qtype == 'url':
if resp.content[:7] == 'http://' or resp.content[:8] == 'https://':
return resp.content
else:
return False
else:
return resp.content
class Confirm(discord.ui.View):
def __init__(self, responders: list, timeout: float = 300.0, label_type: Literal['yes', 'confirm'] = None):
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:
return
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:
return
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:
return
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:
return
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:
return
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:
return
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:
return
self.value = self.options[4]
self.clear_items()
self.stop()
class Pagination(discord.ui.View):
def __init__(self, responders: list, timeout: float = 300.0):
super().__init__(timeout=timeout)
if not isinstance(responders, list):
raise TypeError('responders must be a list')
self.value = None
self.responders = responders
@discord.ui.button(label='⏮️', style=discord.ButtonStyle.blurple)
async def left_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logger.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'left'
await interaction.response.defer()
self.stop()
@discord.ui.button(label='❌️', style=discord.ButtonStyle.secondary)
async def cancel_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logger.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'cancel'
await interaction.response.defer()
self.stop()
@discord.ui.button(label='⏭️', style=discord.ButtonStyle.blurple)
async def right_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logger.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'right'
await interaction.response.defer()
self.stop()
class SelectChoicePackTeam(discord.ui.Select):
def __init__(self, which: Literal['AL', 'NL'], team, cardset_id: Optional[int] = None):
self.which = which
self.owner_team = team
self.cardset_id = cardset_id
if which == 'AL':
options = [
discord.SelectOption(label='Baltimore Orioles'),
discord.SelectOption(label='Boston Red Sox'),
discord.SelectOption(label='Chicago White Sox'),
discord.SelectOption(label='Cleveland Guardians'),
discord.SelectOption(label='Detroit Tigers'),
discord.SelectOption(label='Houston Astros'),
discord.SelectOption(label='Kansas City Royals'),
discord.SelectOption(label='Los Angeles Angels'),
discord.SelectOption(label='Minnesota Twins'),
discord.SelectOption(label='New York Yankees'),
discord.SelectOption(label='Oakland Athletics'),
discord.SelectOption(label='Seattle Mariners'),
discord.SelectOption(label='Tampa Bay Rays'),
discord.SelectOption(label='Texas Rangers'),
discord.SelectOption(label='Toronto Blue Jays')
]
else:
options = [
discord.SelectOption(label='Arizona Diamondbacks'),
discord.SelectOption(label='Atlanta Braves'),
discord.SelectOption(label='Chicago Cubs'),
discord.SelectOption(label='Cincinnati Reds'),
discord.SelectOption(label='Colorado Rockies'),
discord.SelectOption(label='Los Angeles Dodgers'),
discord.SelectOption(label='Miami Marlins'),
discord.SelectOption(label='Milwaukee Brewers'),
discord.SelectOption(label='New York Mets'),
discord.SelectOption(label='Philadelphia Phillies'),
discord.SelectOption(label='Pittsburgh Pirates'),
discord.SelectOption(label='San Diego Padres'),
discord.SelectOption(label='San Francisco Giants'),
discord.SelectOption(label='St. Louis Cardinals'),
discord.SelectOption(label='Washington Nationals')
]
super().__init__(placeholder=f'Select an {which} team', options=options)
async def callback(self, interaction: discord.Interaction):
team_id = None
if self.which == 'AL':
if self.values[0] == 'Baltimore Orioles':
team_id = 3
elif self.values[0] == 'Boston Red Sox':
team_id = 4
elif self.values[0] == 'Chicago White Sox':
team_id = 6
elif self.values[0] == 'Cleveland Guardians':
team_id = 8
elif self.values[0] == 'Detroit Tigers':
team_id = 10
elif self.values[0] == 'Houston Astros':
team_id = 11
elif self.values[0] == 'Kansas City Royals':
team_id = 12
elif self.values[0] == 'Los Angeles Angels':
team_id = 13
elif self.values[0] == 'Minnesota Twins':
team_id = 17
elif self.values[0] == 'New York Yankees':
team_id = 19
elif self.values[0] == 'Oakland Athletics':
team_id = 20
elif self.values[0] == 'Seattle Mariners':
team_id = 24
elif self.values[0] == 'Tampa Bay Rays':
team_id = 27
elif self.values[0] == 'Texas Rangers':
team_id = 28
elif self.values[0] == 'Toronto Blue Jays':
team_id = 29
else:
if self.values[0] == 'Arizona Diamondbacks':
team_id = 1
elif self.values[0] == 'Atlanta Braves':
team_id = 2
elif self.values[0] == 'Chicago Cubs':
team_id = 5
elif self.values[0] == 'Cincinnati Reds':
team_id = 7
elif self.values[0] == 'Colorado Rockies':
team_id = 9
elif self.values[0] == 'Los Angeles Dodgers':
team_id = 14
elif self.values[0] == 'Miami Marlins':
team_id = 15
elif self.values[0] == 'Milwaukee Brewers':
team_id = 16
elif self.values[0] == 'New York Mets':
team_id = 18
elif self.values[0] == 'Philadelphia Phillies':
team_id = 21
elif self.values[0] == 'Pittsburgh Pirates':
team_id = 22
elif self.values[0] == 'San Diego Padres':
team_id = 23
elif self.values[0] == 'San Francisco Giants':
team_id = 25
elif self.values[0] == 'St. Louis Cardinals':
team_id = 26
elif self.values[0] == 'Washington Nationals':
team_id = 30
await interaction.response.edit_message(content=f'You selected the **{self.values[0]}**', view=None)
# Get the selected packs
params = [
('pack_type_id', 8), ('team_id', self.owner_team['id']), ('opened', False), ('limit', 1),
('exact_match', True)
]
if self.cardset_id is not None:
params.append(('pack_cardset_id', self.cardset_id))
p_query = await db_get('packs', params=params)
if p_query['count'] == 0:
logger.error(f'open-packs - no packs found with params: {params}')
raise ValueError(f'Unable to open packs')
this_pack = await db_patch('packs', object_id=p_query['packs'][0]['id'], params=[('pack_team_id', team_id)])
await open_choice_pack(this_pack, self.owner_team, interaction, self.cardset_id)
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):
logger.info(f'SelectPackChoice - selection: {self.values[0]}')
pack_vals = self.values[0].split('-')
logger.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:
logger.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)
class SelectPaperdexCardset(discord.ui.Select):
def __init__(self):
options = [
discord.SelectOption(label='1998 Live'),
discord.SelectOption(label='2024 Season'),
discord.SelectOption(label='2023 Season'),
discord.SelectOption(label='2022 Season'),
discord.SelectOption(label='2022 Promos'),
discord.SelectOption(label='2021 Season'),
discord.SelectOption(label='2019 Season'),
discord.SelectOption(label='2018 Season'),
discord.SelectOption(label='2016 Season'),
discord.SelectOption(label='2013 Season'),
discord.SelectOption(label='2012 Season'),
discord.SelectOption(label='2008 Season'),
discord.SelectOption(label='Mario Super Sluggers')
]
super().__init__(placeholder='Select a Cardset', options=options)
async def callback(self, interaction: discord.Interaction):
logger.info(f'SelectPaperdexCardset - selection: {self.values[0]}')
cardset_id = None
if self.values[0] == '2022 Season':
cardset_id = 3
elif self.values[0] == '2022 Promos':
cardset_id = 4
elif self.values[0] == '2021 Season':
cardset_id = 1
elif self.values[0] == '2019 Season':
cardset_id = 5
elif self.values[0] == '2013 Season':
cardset_id = 6
elif self.values[0] == '2012 Season':
cardset_id = 7
elif self.values[0] == 'Mario Super Sluggers':
cardset_id = 8
elif self.values[0] == '2023 Season':
cardset_id = 9
elif self.values[0] == '2016 Season':
cardset_id = 11
elif self.values[0] == '2008 Season':
cardset_id = 12
elif self.values[0] == '2018 Season':
cardset_id = 13
elif self.values[0] == '2024 Season':
cardset_id = 17
elif self.values[0] == '2024 Promos':
cardset_id = 18
elif self.values[0] == '1998 Live':
cardset_id = 20
c_query = await db_get('cardsets', object_id=cardset_id, none_okay=False)
await interaction.response.edit_message(content=f'Okay, sifting through your cards...', view=None)
cardset_embeds = await paperdex_cardset_embed(
team=await get_team_by_owner(interaction.user.id),
this_cardset=c_query
)
await embed_pagination(cardset_embeds, interaction.channel, interaction.user)
class SelectPaperdexTeam(discord.ui.Select):
def __init__(self, which: Literal['AL', 'NL']):
self.which = which
if which == 'AL':
options = [
discord.SelectOption(label='Baltimore Orioles'),
discord.SelectOption(label='Boston Red Sox'),
discord.SelectOption(label='Chicago White Sox'),
discord.SelectOption(label='Cleveland Guardians'),
discord.SelectOption(label='Detroit Tigers'),
discord.SelectOption(label='Houston Astros'),
discord.SelectOption(label='Kansas City Royals'),
discord.SelectOption(label='Los Angeles Angels'),
discord.SelectOption(label='Minnesota Twins'),
discord.SelectOption(label='New York Yankees'),
discord.SelectOption(label='Oakland Athletics'),
discord.SelectOption(label='Seattle Mariners'),
discord.SelectOption(label='Tampa Bay Rays'),
discord.SelectOption(label='Texas Rangers'),
discord.SelectOption(label='Toronto Blue Jays')
]
else:
options = [
discord.SelectOption(label='Arizona Diamondbacks'),
discord.SelectOption(label='Atlanta Braves'),
discord.SelectOption(label='Chicago Cubs'),
discord.SelectOption(label='Cincinnati Reds'),
discord.SelectOption(label='Colorado Rockies'),
discord.SelectOption(label='Los Angeles Dodgers'),
discord.SelectOption(label='Miami Marlins'),
discord.SelectOption(label='Milwaukee Brewers'),
discord.SelectOption(label='New York Mets'),
discord.SelectOption(label='Philadelphia Phillies'),
discord.SelectOption(label='Pittsburgh Pirates'),
discord.SelectOption(label='San Diego Padres'),
discord.SelectOption(label='San Francisco Giants'),
discord.SelectOption(label='St. Louis Cardinals'),
discord.SelectOption(label='Washington Nationals')
]
super().__init__(placeholder=f'Select an {which} team', options=options)
async def callback(self, interaction: discord.Interaction):
team_id = None
if self.which == 'AL':
if self.values[0] == 'Baltimore Orioles':
team_id = 3
elif self.values[0] == 'Boston Red Sox':
team_id = 4
elif self.values[0] == 'Chicago White Sox':
team_id = 6
elif self.values[0] == 'Cleveland Guardians':
team_id = 8
elif self.values[0] == 'Detroit Tigers':
team_id = 10
elif self.values[0] == 'Houston Astros':
team_id = 11
elif self.values[0] == 'Kansas City Royals':
team_id = 12
elif self.values[0] == 'Los Angeles Angels':
team_id = 13
elif self.values[0] == 'Minnesota Twins':
team_id = 17
elif self.values[0] == 'New York Yankees':
team_id = 19
elif self.values[0] == 'Oakland Athletics':
team_id = 20
elif self.values[0] == 'Seattle Mariners':
team_id = 24
elif self.values[0] == 'Tampa Bay Rays':
team_id = 27
elif self.values[0] == 'Texas Rangers':
team_id = 28
elif self.values[0] == 'Toronto Blue Jays':
team_id = 29
else:
if self.values[0] == 'Arizona Diamondbacks':
team_id = 1
elif self.values[0] == 'Atlanta Braves':
team_id = 2
elif self.values[0] == 'Chicago Cubs':
team_id = 5
elif self.values[0] == 'Cincinnati Reds':
team_id = 7
elif self.values[0] == 'Colorado Rockies':
team_id = 9
elif self.values[0] == 'Los Angeles Dodgers':
team_id = 14
elif self.values[0] == 'Miami Marlins':
team_id = 15
elif self.values[0] == 'Milwaukee Brewers':
team_id = 16
elif self.values[0] == 'New York Mets':
team_id = 18
elif self.values[0] == 'Philadelphia Phillies':
team_id = 21
elif self.values[0] == 'Pittsburgh Pirates':
team_id = 22
elif self.values[0] == 'San Diego Padres':
team_id = 23
elif self.values[0] == 'San Francisco Giants':
team_id = 25
elif self.values[0] == 'St. Louis Cardinals':
team_id = 26
elif self.values[0] == 'Washington Nationals':
team_id = 30
t_query = await db_get('teams', object_id=team_id, none_okay=False)
await interaction.response.edit_message(content=f'Okay, sifting through your cards...', view=None)
team_embeds = await paperdex_team_embed(team=await get_team_by_owner(interaction.user.id), mlb_team=t_query)
await embed_pagination(team_embeds, interaction.channel, interaction.user)
class SelectBuyPacksCardset(discord.ui.Select):
def __init__(self, team: dict, quantity: int, pack_type_id: int, pack_embed: discord.Embed, cost: int):
options = [
discord.SelectOption(label='1998 Live'),
discord.SelectOption(label='Pokemon - Brilliant Stars'),
discord.SelectOption(label='2024 Season'),
discord.SelectOption(label='2023 Season'),
discord.SelectOption(label='2022 Season'),
discord.SelectOption(label='2021 Season'),
discord.SelectOption(label='2019 Season'),
discord.SelectOption(label='2018 Season'),
discord.SelectOption(label='2016 Season'),
discord.SelectOption(label='2013 Season'),
discord.SelectOption(label='2012 Season'),
discord.SelectOption(label='2008 Season')
]
self.team = team
self.quantity = quantity
self.pack_type_id = pack_type_id
self.pack_embed = pack_embed
self.cost = cost
super().__init__(placeholder='Select a Cardset', options=options)
async def callback(self, interaction: discord.Interaction):
logger.info(f'SelectBuyPacksCardset - selection: {self.values[0]}')
cardset_id = None
if self.values[0] == '2022 Season':
cardset_id = 3
elif self.values[0] == '2021 Season':
cardset_id = 1
elif self.values[0] == '2019 Season':
cardset_id = 5
elif self.values[0] == '2013 Season':
cardset_id = 6
elif self.values[0] == '2012 Season':
cardset_id = 7
elif self.values[0] == '2023 Season':
cardset_id = 9
elif self.values[0] == '2016 Season':
cardset_id = 11
elif self.values[0] == '2008 Season':
cardset_id = 12
elif self.values[0] == '2018 Season':
cardset_id = 13
elif self.values[0] == '2024 Season':
cardset_id = 17
elif self.values[0] == '1998 Live':
cardset_id = 20
elif self.values[0] == 'Pokemon - Brilliant Stars':
cardset_id = 23
self.pack_embed.set_image(url=IMAGES['pack-pkmnbs'])
self.pack_embed.description = f'{self.pack_embed.description} - {self.values[0]}'
view = Confirm(responders=[interaction.user], timeout=30)
await interaction.response.edit_message(
content=None,
embed=self.pack_embed,
view=None
)
question = await interaction.channel.send(
content=f'Your Wallet: {self.team["wallet"]}\n'
f'Pack{"s" if self.quantity > 1 else ""} Price: {self.cost}\n'
f'After Purchase: {self.team["wallet"] - self.cost}\n\n'
f'Would you like to make this purchase?',
view=view
)
await view.wait()
if not view.value:
await question.edit(
content='Saving that money. Smart.',
view=None
)
return
p_model = {
'team_id': self.team['id'],
'pack_type_id': self.pack_type_id,
'pack_cardset_id': cardset_id
}
await db_post('packs', payload={'packs': [p_model for x in range(self.quantity)]})
await db_post(f'teams/{self.team["id"]}/money/-{self.cost}')
await question.edit(
content=f'{"They are" if self.quantity > 1 else "It is"} all yours! Go rip \'em with `/open-packs`',
view=None
)
class SelectBuyPacksTeam(discord.ui.Select):
def __init__(
self, which: Literal['AL', 'NL'], team: dict, quantity: int, pack_type_id: int, pack_embed: discord.Embed,
cost: int):
self.which = which
self.team = team
self.quantity = quantity
self.pack_type_id = pack_type_id
self.pack_embed = pack_embed
self.cost = cost
if which == 'AL':
options = [
discord.SelectOption(label='Baltimore Orioles'),
discord.SelectOption(label='Boston Red Sox'),
discord.SelectOption(label='Chicago White Sox'),
discord.SelectOption(label='Cleveland Guardians'),
discord.SelectOption(label='Detroit Tigers'),
discord.SelectOption(label='Houston Astros'),
discord.SelectOption(label='Kansas City Royals'),
discord.SelectOption(label='Los Angeles Angels'),
discord.SelectOption(label='Minnesota Twins'),
discord.SelectOption(label='New York Yankees'),
discord.SelectOption(label='Oakland Athletics'),
discord.SelectOption(label='Seattle Mariners'),
discord.SelectOption(label='Tampa Bay Rays'),
discord.SelectOption(label='Texas Rangers'),
discord.SelectOption(label='Toronto Blue Jays')
]
else:
options = [
discord.SelectOption(label='Arizona Diamondbacks'),
discord.SelectOption(label='Atlanta Braves'),
discord.SelectOption(label='Chicago Cubs'),
discord.SelectOption(label='Cincinnati Reds'),
discord.SelectOption(label='Colorado Rockies'),
discord.SelectOption(label='Los Angeles Dodgers'),
discord.SelectOption(label='Miami Marlins'),
discord.SelectOption(label='Milwaukee Brewers'),
discord.SelectOption(label='New York Mets'),
discord.SelectOption(label='Philadelphia Phillies'),
discord.SelectOption(label='Pittsburgh Pirates'),
discord.SelectOption(label='San Diego Padres'),
discord.SelectOption(label='San Francisco Giants'),
discord.SelectOption(label='St. Louis Cardinals'),
discord.SelectOption(label='Washington Nationals')
]
super().__init__(placeholder=f'Select an {which} team', options=options)
async def callback(self, interaction: discord.Interaction):
team_id = None
if self.which == 'AL':
if self.values[0] == 'Baltimore Orioles':
team_id = 3
elif self.values[0] == 'Boston Red Sox':
team_id = 4
elif self.values[0] == 'Chicago White Sox':
team_id = 6
elif self.values[0] == 'Cleveland Guardians':
team_id = 8
elif self.values[0] == 'Detroit Tigers':
team_id = 10
elif self.values[0] == 'Houston Astros':
team_id = 11
elif self.values[0] == 'Kansas City Royals':
team_id = 12
elif self.values[0] == 'Los Angeles Angels':
team_id = 13
elif self.values[0] == 'Minnesota Twins':
team_id = 17
elif self.values[0] == 'New York Yankees':
team_id = 19
elif self.values[0] == 'Oakland Athletics':
team_id = 20
elif self.values[0] == 'Seattle Mariners':
team_id = 24
elif self.values[0] == 'Tampa Bay Rays':
team_id = 27
elif self.values[0] == 'Texas Rangers':
team_id = 28
elif self.values[0] == 'Toronto Blue Jays':
team_id = 29
else:
if self.values[0] == 'Arizona Diamondbacks':
team_id = 1
elif self.values[0] == 'Atlanta Braves':
team_id = 2
elif self.values[0] == 'Chicago Cubs':
team_id = 5
elif self.values[0] == 'Cincinnati Reds':
team_id = 7
elif self.values[0] == 'Colorado Rockies':
team_id = 9
elif self.values[0] == 'Los Angeles Dodgers':
team_id = 14
elif self.values[0] == 'Miami Marlins':
team_id = 15
elif self.values[0] == 'Milwaukee Brewers':
team_id = 16
elif self.values[0] == 'New York Mets':
team_id = 18
elif self.values[0] == 'Philadelphia Phillies':
team_id = 21
elif self.values[0] == 'Pittsburgh Pirates':
team_id = 22
elif self.values[0] == 'San Diego Padres':
team_id = 23
elif self.values[0] == 'San Francisco Giants':
team_id = 25
elif self.values[0] == 'St. Louis Cardinals':
team_id = 26
elif self.values[0] == 'Washington Nationals':
team_id = 30
self.pack_embed.description = f'{self.pack_embed.description} - {self.values[0]}'
view = Confirm(responders=[interaction.user], timeout=30)
await interaction.response.edit_message(
content=None,
embed=self.pack_embed,
view=None
)
question = await interaction.channel.send(
content=f'Your Wallet: {self.team["wallet"]}\n'
f'Pack{"s" if self.quantity > 1 else ""} Price: {self.cost}\n'
f'After Purchase: {self.team["wallet"] - self.cost}\n\n'
f'Would you like to make this purchase?',
view=view
)
await view.wait()
if not view.value:
await question.edit(
content='Saving that money. Smart.',
view=None
)
return
p_model = {
'team_id': self.team['id'],
'pack_type_id': self.pack_type_id,
'pack_team_id': team_id
}
await db_post('packs', payload={'packs': [p_model for x in range(self.quantity)]})
await db_post(f'teams/{self.team["id"]}/money/-{self.cost}')
await question.edit(
content=f'{"They are" if self.quantity > 1 else "It is"} all yours! Go rip \'em with `/open-packs`',
view=None
)
class SelectUpdatePlayerTeam(discord.ui.Select):
def __init__(self, which: Literal['AL', 'NL'], player: dict, reporting_team: dict, bot):
self.bot = bot
self.which = which
self.player = player
self.reporting_team = reporting_team
if which == 'AL':
options = [
discord.SelectOption(label='Baltimore Orioles'),
discord.SelectOption(label='Boston Red Sox'),
discord.SelectOption(label='Chicago White Sox'),
discord.SelectOption(label='Cleveland Guardians'),
discord.SelectOption(label='Detroit Tigers'),
discord.SelectOption(label='Houston Astros'),
discord.SelectOption(label='Kansas City Royals'),
discord.SelectOption(label='Los Angeles Angels'),
discord.SelectOption(label='Minnesota Twins'),
discord.SelectOption(label='New York Yankees'),
discord.SelectOption(label='Oakland Athletics'),
discord.SelectOption(label='Seattle Mariners'),
discord.SelectOption(label='Tampa Bay Rays'),
discord.SelectOption(label='Texas Rangers'),
discord.SelectOption(label='Toronto Blue Jays')
]
else:
options = [
discord.SelectOption(label='Arizona Diamondbacks'),
discord.SelectOption(label='Atlanta Braves'),
discord.SelectOption(label='Chicago Cubs'),
discord.SelectOption(label='Cincinnati Reds'),
discord.SelectOption(label='Colorado Rockies'),
discord.SelectOption(label='Los Angeles Dodgers'),
discord.SelectOption(label='Miami Marlins'),
discord.SelectOption(label='Milwaukee Brewers'),
discord.SelectOption(label='New York Mets'),
discord.SelectOption(label='Philadelphia Phillies'),
discord.SelectOption(label='Pittsburgh Pirates'),
discord.SelectOption(label='San Diego Padres'),
discord.SelectOption(label='San Francisco Giants'),
discord.SelectOption(label='St. Louis Cardinals'),
discord.SelectOption(label='Washington Nationals')
]
super().__init__(placeholder=f'Select an {which} team', options=options)
async def callback(self, interaction: discord.Interaction):
if self.values[0] == self.player['franchise'] or self.values[0] == self.player['mlbclub']:
await interaction.response.send_message(
content=f'Thank you for the help, but it looks like somebody beat you to it! '
f'**{player_desc(self.player)}** is already assigned to the **{self.player["mlbclub"]}**.'
)
return
view = Confirm(responders=[interaction.user], timeout=15)
await interaction.response.edit_message(
content=f'Should I update **{player_desc(self.player)}**\'s team to the **{self.values[0]}**?',
view=None
)
question = await interaction.channel.send(
content=None,
view=view
)
await view.wait()
if not view.value:
await question.edit(
content='That didnt\'t sound right to me, either. Let\'s not touch that.',
view=None
)
return
else:
await question.delete()
await db_patch('players', object_id=self.player['player_id'], params=[
('mlbclub', self.values[0]), ('franchise', self.values[0])
])
await db_post(f'teams/{self.reporting_team["id"]}/money/25')
await send_to_channel(
self.bot, 'pd-news-ticker',
content=f'{interaction.user.name} just updated **{player_desc(self.player)}**\'s team to the '
f'**{self.values[0]}**'
)
await interaction.channel.send(f'All done!')
class SelectView(discord.ui.View):
def __init__(self, select_objects: list[discord.ui.Select], timeout: float = 300.0):
super().__init__(timeout=timeout)
for x in select_objects:
self.add_item(x)
class Dropdown(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):
def __init__(self, dropdown_objects: list[Dropdown], timeout: float = 300.0):
super().__init__(timeout=timeout)
# self.add_item(Dropdown())
for x in dropdown_objects:
self.add_item(x)
def random_conf_gif():
conf_gifs = [
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/explosion-boom-iron-man-gif-14282225',
'https://tenor.com/view/betty-white-dab-consider-it-done-gif-11972415',
'https://tenor.com/view/done-and-done-spongebob-finished-just-did-it-gif-10843280',
'https://tenor.com/view/thumbs-up-okay-ok-well-done-gif-13840394',
'https://tenor.com/view/tinkerbell-peter-pan-all-done-gif-15003723',
'https://tenor.com/view/done-and-done-ron-swanson-gotchu-gif-10843254',
'https://tenor.com/view/sponge-bob-thumbs-up-ok-smile-gif-12038157',
'https://tenor.com/view/thumbs-up-cool-okay-bye-gif-8633196',
'https://i0.wp.com/media1.giphy.com/media/iwvuPyfi7z14I/giphy.gif',
'https://media1.tenor.com/images/859a2d3b201fbacec13904242976b9e0/tenor.gif',
'https://tenor.com/bc1OJ.gif',
'https://tenor.com/1EmF.gif',
'https://tenor.com/ZYCh.gif',
'https://tenor.com/patd.gif',
'https://tenor.com/u6mU.gif',
'https://tenor.com/x2sa.gif',
'https://tenor.com/bAVeS.gif',
'https://tenor.com/bxOcj.gif',
'https://tenor.com/ETJ7.gif',
'https://tenor.com/bpH3g.gif',
'https://tenor.com/biF9q.gif',
'https://tenor.com/OySS.gif',
'https://tenor.com/bvVFv.gif',
'https://tenor.com/bFeqA.gif'
]
return conf_gifs[random.randint(0, len(conf_gifs) - 1)]
def random_no_gif():
no_gifs = [
'https://tenor.com/view/youre-not-my-dad-dean-jensen-ackles-supernatural-you-arent-my-dad-gif-19503399',
'https://tenor.com/view/youre-not-my-dad-kid-gif-8300190',
'https://tenor.com/view/youre-not-my-supervisor-youre-not-my-boss-gif-12971403',
'https://tenor.com/view/dont-tell-me-what-to-do-gif-4951202'
]
return no_gifs[random.randint(0, len(no_gifs) - 1)]
def random_salute_gif():
salute_gifs = [
'https://media.giphy.com/media/fSAyceY3BCgtiQGnJs/giphy.gif',
'https://media.giphy.com/media/bsWDUSFUmJCOk/giphy.gif',
'https://media.giphy.com/media/hStvd5LiWCFzYNyxR4/giphy.gif',
'https://media.giphy.com/media/RhSR5xXDsXJ7jbnrRW/giphy.gif',
'https://media.giphy.com/media/lNQvrlPdbmZUU2wlh9/giphy.gif',
'https://gfycat.com/skeletaldependableandeancat',
'https://i.gifer.com/5EJk.gif',
'https://tenor.com/baJUV.gif',
'https://tenor.com/bdnQH.gif',
'https://tenor.com/bikQU.gif',
'https://i.pinimg.com/originals/04/36/bf/0436bfc9861b4b57ffffda82d3adad6e.gif',
'https://media.giphy.com/media/6RtOG4Q7v34kw/giphy.gif',
'https://keyassets-p2.timeincuk.net/wp/prod/wp-content/uploads/sites/42/2017/04/anigif_'
'enhanced-946-1433453114-7.gif',
'https://keyassets-p2.timeincuk.net/wp/prod/wp-content/uploads/sites/42/2017/04/100c5d677cc28ea3f15'
'4c70d641f655b_meme-crying-gif-crying-gif-meme_620-340.gif',
'https://media.giphy.com/media/fnKd6rCHaZoGdzLjjA/giphy.gif',
'https://media.giphy.com/media/47D5jmVc4f7ylygXYD/giphy.gif',
'https://media.giphy.com/media/I4wGMXoi2kMDe/giphy.gif',
]
return salute_gifs[random.randint(0, len(salute_gifs) - 1)]
def random_conf_word():
conf_words = [
'dope',
'cool',
'got it',
'noice',
'ok',
'lit',
]
return conf_words[random.randint(0, len(conf_words) - 1)]
def random_codename():
all_names = [
'Shong', 'DerekSux', 'JoeSux', 'CalSux', 'Friend', 'Andrea', 'Ent', 'Lindved', 'Camp', 'Idyll', 'Elaphus',
'Turki', 'Shrimp', 'Primary', 'Anglica', 'Shail', 'Blanket', 'Baffled', 'Deer', 'Thisted', 'Brisk', 'Shy',
'Table', 'Jorts', 'Renati', 'Gisky', 'Prig', 'Bathtub', 'Gallery', 'Mavas', 'Chird', 'Oxyura', 'Mydal', 'Brown',
'Vasen', 'Worthy', 'Bivver', 'Cirlus', 'Self', 'Len', 'Sharp', 'Dart', 'Crepis', 'Ferina', 'Curl', 'Lancome',
'Stuff', 'Glove', 'Consist', 'Smig', 'Egg', 'Pleat', 'Picture', 'Spin', 'Ridgty', 'Ickled', 'Abashed', 'Haul',
'Cordage', 'Chivery', 'Stointy', 'Baa', 'Here', 'Ulmi', 'Tour', 'Tribe', 'Crunch', 'Used', 'Pigface', 'Audit',
'Written', 'Once', 'Fickle', 'Drugged', 'Swarm', 'Blimber', 'Torso', 'Retusa', 'Hockey', 'Pusty', 'Sallow',
'Next', 'Mansion', 'Glass', 'Screen', 'Josiah', 'Bonkey', 'Stuff', 'Sane', 'Blooded', 'Gnat', 'Liparis',
'Ocean', 'Sway', 'Roband', 'Still', 'Ribba', 'Biryani', 'Halibut', 'Flyn', 'Until', 'Depend', 'Intel',
'Affinis', 'Chef', 'Trounce', 'Crawl', 'Grab', 'Eggs', 'Malfroy', 'Sitta', 'Cretin', 'May', 'Smithii',
'Saffron', 'Crummy', 'Powered', 'Rail', 'Trait', 'Koiled', 'Bronze', 'Quickly', 'Vikis', 'Trift', 'Jubilar',
'Deft', 'Juncus', 'Sodding', 'Distant', 'Poecile', 'Pipe', 'Sell', 'Inops', 'Peusi', 'Sparrow', 'Yams',
'Kidneys', 'Artery', 'Vuffin', 'Boink', 'Bos', 'Notable', 'Alba', 'Spurge', 'Ruby', 'Cilia', 'Pellow', 'Nox',
'Woozy', 'Semvik', 'Tyda', 'Season', 'Lychnis', 'Ibestad', 'Bagge', 'Marked', 'Browdie', 'Fisher', 'Tilly',
'Troll', 'Gypsy', 'Thisted', 'Flirt', 'Stop', 'Radiate', 'Poop', 'Plenty', 'Jeff', 'Magpie', 'Roof', 'Ent',
'Dumbo', 'Pride', 'Weights', 'Winted', 'Dolden', 'Meotica', 'Yikes', 'Teeny', 'Fizz', 'Eide', 'Foetida',
'Crash', 'Mann', 'Salong', 'Cetti', 'Balloon', 'Petite', 'Find', 'Sputter', 'Patula', 'Upstage', 'Aurora',
'Dadson', 'Drate', 'Heidal', 'Robin', 'Auditor', 'Ithil', 'Warmen', 'Pat', 'Muppet', '007', 'Advantage',
'Alert', 'Backhander', 'Badass', 'Blade', 'Blaze', 'Blockade', 'Blockbuster', 'Boxer', 'Brimstone', 'Broadway',
'Buccaneer', 'Champion', 'Cliffhanger', 'Coachman', 'Comet', 'Commander', 'Courier', 'Cowboy', 'Crawler',
'Crossroads', 'DeepSpace', 'Desperado', 'Double-Decker', 'Echelon', 'Edge', 'Encore', 'EnRoute', 'Escape',
'Eureka', 'Evangelist', 'Excursion', 'Explorer', 'Fantastic', 'Firefight', 'Foray', 'Forge', 'Freeway',
'Frontier', 'FunMachine', 'Galaxy', 'GameOver', 'Genesis', 'Hacker', 'Hawkeye', 'Haybailer', 'Haystack',
'Hexagon', 'Hitman', 'Hustler', 'Iceberg', 'Impossible', 'Impulse', 'Invader', 'Inventor', 'IronWolf',
'Jackrabbit', 'Juniper', 'Keyhole', 'Lancelot', 'Liftoff', 'MadHatter', 'Magnum', 'Majestic', 'Merlin',
'Multiplier', 'Netiquette', 'Nomad', 'Octagon', 'Offense', 'OliveBranch', 'OlympicTorch', 'Omega', 'Onyx',
'Orbit', 'OuterSpace', 'Outlaw', 'Patron', 'Patriot', 'Pegasus', 'Pentagon', 'Pilgrim', 'Pinball', 'Pinnacle',
'Pipeline', 'Pirate', 'Portal', 'Predator', 'Prism', 'RagingBull', 'Ragtime', 'Reunion', 'Ricochet',
'Roadrunner', 'Rockstar', 'RobinHood', 'Rover', 'Runabout', 'Sapphire', 'Scrappy', 'Seige', 'Shadow',
'Shakedown', 'Shockwave', 'Shooter', 'Showdown', 'SixPack', 'SlamDunk', 'Slasher', 'Sledgehammer', 'Spirit',
'Spotlight', 'Starlight', 'Steamroller', 'Stride', 'Sunrise', 'Superhuman', 'Supernova', 'SuperBowl', 'Sunset',
'Sweetheart', 'TopHand', 'Touchdown', 'Tour', 'Trailblazer', 'Transit', 'Trekker', 'Trio', 'TriplePlay',
'TripleThreat', 'Universe', 'Unstoppable', 'Utopia', 'Vicinity', 'Vector', 'Vigilance', 'Vigilante', 'Vista',
'Visage', 'Vis-à-vis', 'VIP', 'Volcano', 'Volley', 'Whizzler', 'Wingman', 'Badger', 'BlackCat', 'Bobcat',
'Caracal', 'Cheetah', 'Cougar', 'Jaguar', 'Leopard', 'Lion', 'Lynx', 'MountainLion', 'Ocelot', 'Panther',
'Puma', 'Siamese', 'Serval', 'Tiger', 'Wolverine', 'Abispa', 'Andrena', 'BlackWidow', 'Cataglyphis',
'Centipede', 'Cephalotes', 'Formica', 'Hornet', 'Jellyfish', 'Scorpion', 'Tarantula', 'Yellowjacket', 'Wasp',
'Apollo', 'Ares', 'Artemis', 'Athena', 'Hercules', 'Hermes', 'Iris', 'Medusa', 'Nemesis', 'Neptune', 'Perseus',
'Poseidon', 'Triton', 'Zeus', 'Aquarius', 'Aries', 'Cancer', 'Capricorn', 'Gemini', 'Libra', 'Leo', 'Pisces',
'Sagittarius', 'Scorpio', 'Taurus', 'Virgo', 'Andromeda', 'Aquila', 'Cassiopeia', 'Cepheus', 'Cygnus',
'Delphinus', 'Drako', 'Lyra', 'Orion', 'Perseus', 'Serpens', 'Triangulum', 'Anaconda', 'Boa', 'Cobra',
'Copperhead', 'Cottonmouth', 'Garter', 'Kingsnake', 'Mamba', 'Python', 'Rattler', 'Sidewinder', 'Taipan',
'Viper', 'Alligator', 'Barracuda', 'Crocodile', 'Gator', 'GreatWhite', 'Hammerhead', 'Jaws', 'Lionfish',
'Mako', 'Moray', 'Orca', 'Piranha', 'Shark', 'Stingray', 'Axe', 'BattleAxe', 'Bayonet', 'Blade', 'Crossbowe',
'Dagger', 'Excalibur', 'Halberd', 'Hatchet', 'Machete', 'Saber', 'Samurai', 'Scimitar', 'Scythe', 'Stiletto',
'Spear', 'Sword', 'Aurora', 'Avalanche', 'Blizzard', 'Cyclone', 'Dewdrop', 'Downpour', 'Duststorm', 'Fogbank',
'Freeze', 'Frost', 'GullyWasher', 'Gust', 'Hurricane', 'IceStorm', 'JetStream', 'Lightning', 'Mist', 'Monsoon',
'Rainbow', 'Raindrop', 'SandStorm', 'Seabreeze', 'Snowflake', 'Stratosphere', 'Storm', 'Sunrise', 'Sunset',
'Tornado', 'Thunder', 'Thunderbolt', 'Thunderstorm', 'TropicalStorm', 'Twister', 'Typhoon', 'Updraft', 'Vortex',
'Waterspout', 'Whirlwind', 'WindChill', 'Archimedes', 'Aristotle', 'Confucius', 'Copernicus', 'Curie',
'daVinci', 'Darwin', 'Descartes', 'Edison', 'Einstein', 'Epicurus', 'Freud', 'Galileo', 'Hawking',
'Machiavelli', 'Marx', 'Newton', 'Pascal', 'Pasteur', 'Plato', 'Sagan', 'Socrates', 'Tesla', 'Voltaire',
'Baccarat', 'Backgammon', 'Blackjack', 'Chess', 'Jenga', 'Jeopardy', 'Keno', 'Monopoly', 'Pictionary', 'Poker',
'Scrabble', 'TrivialPursuit', 'Twister', 'Roulette', 'Stratego', 'Yahtzee', 'Aquaman', 'Batman', 'BlackPanther',
'BlackWidow', 'CaptainAmerica', 'Catwoman', 'Daredevil', 'Dr.Strange', 'Flash', 'GreenArrow', 'GreenLantern',
'Hulk', 'IronMan', 'Phantom', 'Thor', 'SilverSurfer', 'SpiderMan', 'Supergirl', 'Superman', 'WonderWoman',
'Wolverine', 'Hypersonic', 'Lightspeed', 'Mach1,2,3,4,etc', 'Supersonic', 'WarpSpeed', 'Amiatina', 'Andalusian',
'Appaloosa', 'Clydesdale', 'Colt', 'Falabella', 'Knabstrupper', 'Lipizzan', 'Lucitano', 'Maverick', 'Mustang',
'Palomino', 'Pony', 'QuarterHorse', 'Stallion', 'Thoroughbred', 'Zebra', 'Antigua', 'Aruba', 'Azores', 'Baja',
'Bali', 'Barbados', 'Bermuda', 'BoraBora', 'Borneo', 'Capri', 'Cayman', 'Corfu', 'Cozumel', 'Curacao', 'Fiji',
'Galapagos', 'Hawaii', 'Ibiza', 'Jamaica', 'Kauai', 'Lanai', 'Majorca', 'Maldives', 'Maui', 'Mykonos',
'Nantucket', 'Oahu', 'Tahiti', 'Tortuga', 'Roatan', 'Santorini', 'Seychelles', 'St.Johns', 'St.Lucia',
'Albatross', 'BaldEagle', 'Blackhawk', 'BlueJay', 'Chukar', 'Condor', 'Crane', 'Dove', 'Eagle', 'Falcon',
'Goose(GoldenGoose)', 'Grouse', 'Hawk', 'Heron', 'Hornbill', 'Hummingbird', 'Lark', 'Mallard', 'Oriole',
'Osprey', 'Owl', 'Parrot', 'Penguin', 'Peregrine', 'Pelican', 'Pheasant', 'Quail', 'Raptor', 'Raven', 'Robin',
'Sandpiper', 'Seagull', 'Sparrow', 'Stork', 'Thunderbird', 'Toucan', 'Vulture', 'Waterfowl', 'Woodpecker',
'Wren', 'C-3PO', 'Chewbacca', 'Dagobah', 'DarthVader', 'DeathStar', 'Devaron', 'Droid', 'Endor', 'Ewok', 'Hoth',
'Jakku', 'Jedi', 'Leia', 'Lightsaber', 'Lothal', 'Naboo', 'Padawan', 'R2-D2', 'Scarif', 'Sith', 'Skywalker',
'Stormtrooper', 'Tatooine', 'Wookie', 'Yoda', 'Zanbar', 'Canoe', 'Catamaran', 'Cruiser', 'Cutter', 'Ferry',
'Galleon', 'Gondola', 'Hovercraft', 'Hydrofoil', 'Jetski', 'Kayak', 'Longboat', 'Motorboat', 'Outrigger',
'PirateShip', 'Riverboat', 'Sailboat', 'Skipjack', 'Schooner', 'Skiff', 'Sloop', 'Steamboat', 'Tanker',
'Trimaran', 'Trawler', 'Tugboat', 'U-boat', 'Yacht', 'Yawl', 'Lancer', 'Volunteer', 'Searchlight', 'Passkey',
'Deacon', 'Rawhide', 'Timberwolf', 'Eagle', 'Tumbler', 'Renegade', 'Mogul'
]
this_name = all_names[random.randint(0, len(all_names) - 1)]
return this_name
def random_no_phrase():
phrases = [
'uhh...no',
'lol no',
'nope',
]
async def send_to_bothole(ctx, content, embed):
await discord.utils.get(ctx.guild.text_channels, name='pd-bot-hole') \
.send(content=content, embed=embed)
async def send_to_news(ctx, content, embed):
await discord.utils.get(ctx.guild.text_channels, name='pd-news-ticker') \
.send(content=content, embed=embed)
async def typing_pause(ctx, seconds=1):
async with ctx.typing():
await asyncio.sleep(seconds)
async def pause_then_type(ctx, message):
async with ctx.typing():
await asyncio.sleep(len(message) / 100)
await ctx.send(message)
async def check_if_pdhole(ctx):
if ctx.message.channel.name != 'pd-bot-hole':
await ctx.send('Slide on down to my bot-hole for running commands.')
await ctx.message.add_reaction('')
return False
return True
def get_roster_sheet_legacy(team):
return f'https://docs.google.com/spreadsheets/d/{team.gsheet}/edit'
def get_special_embed(special):
embed = discord.Embed(title=f'{special.name} - Special #{special.get_id()}',
color=discord.Color.random(),
description=f'{special.short_desc}')
embed.add_field(name='Description', value=f'{special.long_desc}', inline=False)
# embed.add_field(name='To Redeem', value=f'Run .redeem {special.get_id()}', inline=False)
if special.thumbnail.lower() != 'none':
embed.set_thumbnail(url=f'{special.thumbnail}')
if special.url.lower() != 'none':
embed.set_image(url=f'{special.url}')
return embed
def get_random_embed(title, thumb=None):
embed = discord.Embed(title=title, color=discord.Color.random())
if thumb:
embed.set_thumbnail(url=thumb)
return embed
async def get_player_photo(player):
search_term = player['bbref_id'] if player['bbref_id'] else player['p_name']
req_url = f'https://www.thesportsdb.com/api/v1/json/1/searchplayers.php?p={search_term}'
try:
resp = requests.get(req_url, timeout=.5)
except Exception as e:
return None
if resp.status_code == 200 and resp.json()['player']:
if resp.json()['player'][0]['strSport'] == 'Baseball':
await db_patch('players', object_id=player['player_id'],
params=[('headshot', resp.json()['player'][0]['strThumb'])])
return resp.json()['player'][0]['strThumb']
return None
async def get_player_headshot(player):
search_term = player['bbref_id'] if player['bbref_id'] else player['p_name']
req_url = f'https://www.baseball-reference.com/search/search.fcgi?search={search_term}'
try:
resp = requests.get(req_url, timeout=2).text
soup = BeautifulSoup(resp, 'html.parser')
for item in soup.find_all('img'):
if 'headshot' in item['src']:
await db_patch('players', object_id=player['player_id'], params=[('headshot', item['src'])])
return item['src']
except:
pass
return await get_player_photo(player)
def fuzzy_search(name, master_list):
if name.lower() in master_list:
return name.lower()
great_matches = get_close_matches(name, master_list, cutoff=0.8)
if len(great_matches) == 1:
return great_matches[0]
elif len(great_matches) > 0:
matches = great_matches
else:
matches = get_close_matches(name, master_list, n=6)
if len(matches) == 1:
return matches[0]
if not matches:
raise ValueError(f'{name.title()} was not found')
return matches[0]
async def fuzzy_player_search(ctx, channel, bot, name, master_list):
"""
Takes a name to search and returns the name of the best match
:param ctx: discord context
:param channel: discord channel
:param bot: discord.py bot object
:param name: string
:param master_list: list of names
:return:
"""
matches = fuzzy_search(name, master_list)
embed = discord.Embed(
title="Did You Mean...",
description='Enter the number of the card you would like to see.',
color=0x7FC600
)
count = 1
for x in matches:
embed.add_field(name=f'{count}', value=x, inline=False)
count += 1
embed.set_footer(text='These are the closest matches. Spell better if they\'re not who you want.')
this_q = Question(bot, channel, None, 'int', 45, embed=embed)
resp = await this_q.ask([ctx.author])
if not resp:
return None
if resp < count:
return matches[resp - 1]
else:
raise ValueError(f'{resp} is not a valid response.')
async def create_channel_old(
ctx, channel_name: str, category_name: str, everyone_send=False, everyone_read=True, allowed_members=None,
allowed_roles=None):
this_category = discord.utils.get(ctx.guild.categories, name=category_name)
if not this_category:
raise ValueError(f'I couldn\'t find a category named **{category_name}**')
overwrites = {
ctx.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True),
ctx.guild.default_role: discord.PermissionOverwrite(read_messages=everyone_read, send_messages=everyone_send)
}
if allowed_members:
if isinstance(allowed_members, list):
for member in allowed_members:
overwrites[member] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
if allowed_roles:
if isinstance(allowed_roles, list):
for role in allowed_roles:
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
this_channel = await ctx.guild.create_text_channel(
channel_name,
overwrites=overwrites,
category=this_category
)
logger.info(f'Creating channel ({channel_name}) in ({category_name})')
return this_channel
async def react_and_reply(ctx, reaction, message):
await ctx.message.add_reaction(reaction)
await ctx.send(message)
async def send_to_channel(bot, channel_name, content=None, embed=None):
guild = bot.get_guild(int(os.environ.get('GUILD_ID')))
if not guild:
logger.error('Cannot send to channel - bot not logged in')
return
this_channel = discord.utils.get(guild.text_channels, name=channel_name)
if not this_channel:
this_channel = discord.utils.get(guild.text_channels, id=channel_name)
if not this_channel:
raise NameError(f'**{channel_name}** channel not found')
return await this_channel.send(content=content, embed=embed)
async def get_or_create_role(ctx, role_name, mentionable=True):
this_role = discord.utils.get(ctx.guild.roles, name=role_name)
# logger.info(f'this_role: {this_role} / role_name: {role_name} (POST SEARCH)')
if not this_role:
this_role = await ctx.guild.create_role(name=role_name, mentionable=mentionable)
# logger.info(f'this_role: {this_role} / role_name: {role_name} (PRE RETURN)')
return this_role
"""
NEW FOR SEASON 4
"""
def get_team_embed(title, team=None, thumbnail: bool = True):
if team:
embed = discord.Embed(
title=title,
color=int(team["color"], 16) if team["color"] else int(SBA_COLOR, 16)
)
embed.set_footer(text=f'Paper Dynasty Season {team["season"]}', icon_url=IMAGES['logo'])
if thumbnail:
embed.set_thumbnail(url=team["logo"] if team["logo"] else IMAGES['logo'])
else:
embed = discord.Embed(
title=title,
color=int(SBA_COLOR, 16)
)
embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo'])
if thumbnail:
embed.set_thumbnail(url=IMAGES['logo'])
return embed
async def get_team_by_owner(owner_id: int):
team = await db_get('teams', params=[('gm_id', owner_id)])
if not team['count']:
return None
return team['teams'][0]
async def team_role(ctx, team: Team):
return await get_or_create_role(ctx, f'{team.abbrev} - {team.lname}')
def get_cal_user(ctx):
return ctx.guild.get_member(258104532423147520)
async def get_emoji(ctx, name, return_empty=True):
try:
emoji = await commands.converter.EmojiConverter().convert(ctx, name)
except:
if return_empty:
emoji = ''
else:
return name
return emoji
def get_all_pos(player):
all_pos = []
for x in range(1, 8):
if player[f'pos_{x}']:
all_pos.append(player[f'pos_{x}'])
return all_pos
async def create_channel(
ctx, channel_name: str, category_name: str, everyone_send=False, everyone_read=True,
read_send_members: list = None, read_send_roles: list = None, read_only_roles: list = None):
this_category = discord.utils.get(ctx.guild.categories, name=category_name)
if not this_category:
raise ValueError(f'I couldn\'t find a category named **{category_name}**')
overwrites = {
ctx.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True),
ctx.guild.default_role: discord.PermissionOverwrite(read_messages=everyone_read, send_messages=everyone_send)
}
if read_send_members:
for member in read_send_members:
overwrites[member] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
if read_send_roles:
for role in read_send_roles:
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
if read_only_roles:
for role in read_only_roles:
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=False)
this_channel = await ctx.guild.create_text_channel(
channel_name,
overwrites=overwrites,
category=this_category
)
logger.info(f'Creating channel ({channel_name}) in ({category_name})')
return this_channel
async def share_channel(channel, user, read_only=False):
await channel.set_permissions(user, read_messages=True, send_messages=not read_only)
async def get_card_embeds(card, include_stats=False) -> list:
embed = discord.Embed(
title=f'{card["player"]["p_name"]}',
color=int(card['player']['rarity']['color'], 16)
)
# embed.description = card['team']['lname']
embed.description = f'{card["player"]["cardset"]["name"]} / {card["player"]["mlbclub"]}'
embed.set_author(name=card['team']['lname'], url=IMAGES['logo'], icon_url=card['team']['logo'])
embed.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo'])
if include_stats:
b_query = await db_get(
'plays/batting', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)])
p_query = await db_get(
'plays/pitching', params=[('player_id', card['player']['player_id']), ('season', PD_SEASON)])
embed.add_field(name='Player ID', value=f'{card["player"]["player_id"]}')
embed.add_field(name='Rarity', value=f'{card["player"]["rarity"]["name"]}')
embed.add_field(name='Cost', value=f'{card["player"]["cost"]}')
pos_string = ", ".join(get_all_pos(card['player']))
embed.add_field(name='Positions', value=pos_string)
# all_dex = card['player']['paperdex']
all_dex = await db_get('paperdex', params=[("player_id", card["player"]["player_id"]), ('flat', True)])
count = all_dex['count']
if card['team']['lname'] != 'Paper Dynasty':
bool_list = [True for elem in all_dex['paperdex'] if elem['team'] == card['team']['id']]
if any(bool_list):
if count == 1:
coll_string = f'Only you'
else:
coll_string = f'You and {count - 1} other{"s" if count - 1 != 1 else ""}'
elif count:
coll_string = f'{count} other team{"s" if count != 1 else ""}'
else:
coll_string = f'0 teams'
embed.add_field(name='Collected By', value=coll_string)
else:
embed.add_field(name='Collected By', value=f'{count} team{"s" if count != 1 else ""}')
# TODO: check for dupes with the included paperdex data
# if card['team']['lname'] != 'Paper Dynasty':
# team_dex = await db_get('cards', params=[("player_id", card["player"]["player_id"]), ('team_id', card['team']['id'])])
# count = 1 if not team_dex['count'] else team_dex['count']
# embed.add_field(name='# Dupes', value=f'{count - 1} dupe{"s" if count - 1 != 1 else ""}')
# embed.add_field(name='Team', value=f'{card["player"]["mlbclub"]}')
if card['player']['franchise'] != 'Pokemon':
player_pages = f'[BBRef]({get_player_url(card["player"], "bbref")})'
else:
player_pages = f'[Pkmn]({PKMN_REF_URL}{card["player"]["bbref_id"]})'
embed.add_field(name='Player Page', value=f'{player_pages}')
embed.set_image(url=card["player"]["image"])
headshot = card['player']['headshot'] if card['player']['headshot'] else await get_player_headshot(card['player'])
if headshot:
embed.set_thumbnail(url=headshot)
else:
embed.set_thumbnail(url=IMAGES['logo'])
if card['player']['franchise'] == 'Pokemon':
if card['player']['fangr_id'] is not None:
try:
evo_mon = await db_get('players', object_id=card['player']['fangr_id'], none_okay=True)
if evo_mon is not None:
embed.add_field(
name='Evolves Into',
value=f'{evo_mon["p_name"]}'
)
except Exception as e:
logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True)
if '420420' not in card['player']['strat_code']:
try:
evo_mon = await db_get('players', object_id=card['player']['strat_code'], none_okay=True)
if evo_mon is not None:
embed.add_field(
name='Evolves From',
value=f'{evo_mon["p_name"]}'
)
except Exception as e:
logging.error('could not pull evolution: {e}', exc_info=True, stack_info=True)
if include_stats:
if b_query['count'] > 0:
b = b_query['stats'][0]
re24 = f'{b["re24"]:.2f}'
batting_string = f'```\n' \
f' AVG OBP SLG\n' \
f' {b["avg"]:.3f} {b["obp"]:.3f} {b["slg"]:.3f}\n``````\n' \
f' OPS wOBA RE24\n' \
f' {b["ops"]:.3f} {b["woba"]:.3f} {re24: ^5}\n``````\n' \
f' PA H RBI 2B 3B HR SB\n' \
f'{b["pa"]: >3} {b["hit"]: ^3} {b["rbi"]: ^3} {b["double"]: >2} {b["triple"]: >2} ' \
f'{b["hr"]: >2} {b["sb"]: >2}```\n'
embed.add_field(name='Batting Stats', value=batting_string, inline=False)
if p_query['count'] > 0:
p = p_query['stats'][0]
ip_whole = math.floor(p['outs'] / 3)
ip_denom = p['outs'] % 3
ips = ip_whole + (ip_denom * 0.1)
kpbb = f'{p["k/bb"]:.1f}'
era = f'{p["era"]:.2f}'
whip = f'{p["whip"]:.2f}'
re24 = f'{p["re24"]:.2f}'
pitching_string = f'```\n' \
f' W-L SV ERA WHIP\n' \
f'{p["win"]: >2}-{p["loss"]: <2} {p["save"]: >2} {era: >5} {whip: >4}\n``````\n' \
f' IP SO K/BB RE24\n' \
f'{ips: >5} {p["so"]: ^3} {kpbb: ^4} {re24: ^5}\n```'
embed.add_field(name='Pitching Stats', value=pitching_string, inline=False)
if not card['player']['image2']:
return [embed]
card_two = discord.Embed(color=int(card['player']['rarity']['color'], 16))
card_two.set_footer(text=f'Paper Dynasty Season {card["team"]["season"]}', icon_url=IMAGES['logo'])
card_two.set_image(url=card['player']['image2'])
return [embed, card_two]
def image_embed(image_url: str, title: str = None, color: str = None, desc: str = None, author_name: str = None,
author_icon: str = None):
embed_color = int(SBA_COLOR, 16)
if color is not None:
embed_color = int(color, 16)
embed = discord.Embed(color=embed_color)
if title is not None:
embed.title = title
if desc is not None:
embed.description = desc
if author_name is not None:
icon = author_icon if author_icon is not None else IMAGES['logo']
embed.set_author(name=author_name, icon_url=icon)
embed.set_footer(text=f'Paper Dynasty Season {PD_SEASON}', icon_url=IMAGES['logo'])
embed.set_image(url=image_url)
return embed
def is_shiny(card):
if card['player']['rarity']['value'] >= 5:
return True
return False
async def display_cards(
cards: list, team: dict, channel, user, bot=None, pack_cover: str = None, cust_message: str = None,
add_roster: bool = True, pack_name: str = None) -> bool:
cards.sort(key=lambda x: x['player']['rarity']['value'])
card_embeds = [await get_card_embeds(x) for x in cards]
page_num = 0 if pack_cover is None else -1
seen_shiny = False
view = Pagination([user], timeout=10)
l_emoji = await get_emoji(channel.guild, 'arrow_left')
r_emoji = await get_emoji(channel.guild, 'arrow_right')
view.left_button.disabled = True
view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}'
view.cancel_button.label = f'Close Pack'
view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}'
if len(cards) == 1:
view.right_button.disabled = True
if pack_cover:
msg = await channel.send(
content=None,
embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=pack_name),
view=view
)
else:
msg = await channel.send(content=None, embeds=card_embeds[page_num], view=view)
if cust_message:
follow_up = await channel.send(cust_message)
else:
follow_up = await channel.send(f'{user.mention} you\'ve got {len(cards)} cards here')
while True:
await view.wait()
if view.value:
if view.value == 'cancel':
await msg.edit(view=None)
if add_roster:
await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}')
return True
if view.value == 'left':
page_num -= 1 if page_num > 0 else 0
if view.value == 'right':
page_num += 1 if page_num <= len(card_embeds) else len(card_embeds)
else:
if page_num == len(card_embeds) - 1:
await msg.edit(view=None)
if add_roster:
await follow_up.edit(content=f'Refresh your cards here: {get_roster_sheet(team)}')
return True
else:
page_num += 1
view.value = None
if is_shiny(cards[page_num]) and not seen_shiny:
seen_shiny = True
view = Pagination([user], timeout=300)
view.cancel_button.style = discord.ButtonStyle.success
view.cancel_button.label = 'Flip!'
view.left_button.label = '-'
view.right_button.label = '-'
view.left_button.disabled = True
view.right_button.disabled = True
await msg.edit(
embed=image_embed(
IMAGES['mvp'][cards[page_num]["player"]["franchise"]],
color='56f1fa',
author_name=team['lname'],
author_icon=team['logo']
),
view=view)
tmp_msg = await channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!')
await follow_up.edit(content=f'<@&1163537676885033010> we\'ve got an MVP!')
await tmp_msg.delete()
await view.wait()
view = Pagination([user], timeout=10)
view.right_button.label = f'Next: {page_num + 2}/{len(card_embeds)}{r_emoji}'
view.cancel_button.label = f'Close Pack'
view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(card_embeds)}'
if page_num == 0:
view.left_button.label = f'{l_emoji}Prev: -/{len(card_embeds)}'
view.left_button.disabled = True
elif page_num == len(card_embeds) - 1:
view.timeout = 600.0
view.right_button.label = f'Next: -/{len(card_embeds)}{r_emoji}'
view.right_button.disabled = True
await msg.edit(content=None, embeds=card_embeds[page_num], view=view)
async def embed_pagination(
all_embeds: list, channel, user: discord.Member, custom_message: str = None,
timeout: int = 10, start_page: int = 0):
if start_page > len(all_embeds) - 1 or start_page < 0:
page_num = 0
else:
page_num = start_page
view = Pagination([user], timeout=timeout)
l_emoji = ''
r_emoji = ''
view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}'
view.cancel_button.label = f'Cancel'
view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}'
if page_num == 0:
view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}'
view.left_button.disabled = True
elif page_num == len(all_embeds) - 1:
view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}'
view.right_button.disabled = True
msg = await channel.send(content=custom_message, embed=all_embeds[page_num], view=view)
while True:
await view.wait()
if view.value:
if view.value == 'cancel':
await msg.edit(view=None)
return True
if view.value == 'left':
page_num -= 1 if page_num > 0 else 0
if view.value == 'right':
page_num += 1 if page_num <= len(all_embeds) else len(all_embeds)
else:
if page_num == len(all_embeds) - 1:
await msg.edit(view=None)
return True
else:
page_num += 1
view.value = None
view = Pagination([user], timeout=timeout)
view.right_button.label = f'Next: {page_num + 2}/{len(all_embeds)}{r_emoji}'
view.cancel_button.label = f'Cancel'
view.left_button.label = f'{l_emoji}Prev: {page_num}/{len(all_embeds)}'
if page_num == 0:
view.left_button.label = f'{l_emoji}Prev: -/{len(all_embeds)}'
view.left_button.disabled = True
elif page_num == len(all_embeds) - 1:
view.timeout = 600.0
view.right_button.label = f'Next: -/{len(all_embeds)}{r_emoji}'
view.right_button.disabled = True
await msg.edit(content=None, embed=all_embeds[page_num], view=view)
def get_roster_sheet(team, allow_embed: bool = False):
return f'{"" if allow_embed else "<"}' \
f'https://docs.google.com/spreadsheets/d/{team["gsheet"]}/edit' \
f'{"" if allow_embed else ">"}'
def get_player_url(player, which="sba"):
if which == 'bbref':
return f'https://www.baseball-reference.com/search/search.fcgi?search={player["bbref_id"]}'
else:
stub_name = player["p_name"].replace(" ", "%20")
return f'https://sombaseball.ddns.net/players?name={stub_name}'
async def bad_channel(ctx):
bad_channels = ['paper-dynasty-chat', 'pd-news-ticker']
if ctx.message.channel.name in bad_channels:
await ctx.message.add_reaction('')
bot_hole = discord.utils.get(
ctx.guild.text_channels,
name=f'pd-bot-hole'
)
await ctx.send(f'Slide on down to the {bot_hole.mention} ;)')
return True
else:
return False
def get_channel(ctx, name) -> Optional[discord.TextChannel]:
channel = discord.utils.get(
ctx.guild.text_channels,
name=name
)
if channel:
return channel
return None
async def get_test_pack(ctx, team):
pull_notifs = []
this_pack = await db_post('packs/one', payload={
'team_id': team['id'], 'pack_type_id': 1,
'open_time': int(datetime.datetime.timestamp(datetime.datetime.now())*1000)
})
ft_query = await db_get('players/random', params=[('max_rarity', 1), ('limit', 3)])
four_query = await db_get('players/random', params=[('min_rarity', 1), ('max_rarity', 3), ('limit', 1)])
five_query = await db_get('players/random', params=[('min_rarity', 5), ('max_rarity', 5), ('limit', 1)])
first_three = ft_query['players']
fourth = four_query['players']
fifth = five_query['players']
all_cards = [*first_three, *fourth, *fifth]
success = await db_post('cards', timeout=10, payload={'cards': [{
'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': this_pack['id']} for x in all_cards]
})
if not success:
await ctx.send(f'I was not able to create these cards {get_emoji(ctx, "slight_frown")}')
return
for x in all_cards:
if x['rarity']['value'] >= 3:
pull_notifs.append(x)
for pull in pull_notifs:
await db_post('notifs', payload={
'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000),
'title': 'Rare Pull',
'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})',
'message': f'Pulled by {team["abbrev"]}',
'about': f'Player-{pull["player_id"]}'
})
return [{'player': x, 'team': team} for x in all_cards]
async def roll_for_cards(all_packs: list, extra_val=None) -> list:
"""
Pack odds are calculated based on the pack type
Parameters
----------
extra_val
all_packs
Returns
-------
"""
all_players = []
team = all_packs[0]['team']
pack_ids = []
for pack in all_packs:
counts = {
'Rep': {
'count': 0,
'rarity': 0
},
'Res': {
'count': 0,
'rarity': 1
},
'Sta': {
'count': 0,
'rarity': 2
},
'All': {
'count': 0,
'rarity': 3
},
'MVP': {
'count': 0,
'rarity': 5
},
'HoF': {
'count': 0,
'rarity': 8
},
}
this_pack_players = []
if pack['pack_type']['name'] == 'Standard':
# Cards 1 - 2
for x in range(2):
d_1000 = random.randint(1, 1000)
if d_1000 <= 450:
counts['Rep']['count'] += 1
elif d_1000 <= 900:
counts['Res']['count'] += 1
else:
counts['Sta']['count'] += 1
# Card 3
d_1000 = random.randint(1, 1000)
if d_1000 <= 350:
counts['Rep']['count'] += 1
elif d_1000 <= 700:
counts['Res']['count'] += 1
elif d_1000 <= 950:
counts['Sta']['count'] += 1
else:
counts['All']['count'] += 1
# Card 4
d_1000 = random.randint(1, 1000)
if d_1000 <= 310:
counts['Rep']['count'] += 1
elif d_1000 <= 620:
counts['Res']['count'] += 1
elif d_1000 <= 940:
counts['Sta']['count'] += 1
elif d_1000 <= 990:
counts['All']['count'] += 1
else:
counts['MVP']['count'] += 1
# Card 5
d_1000 = random.randint(1, 1000)
if d_1000 <= 215:
counts['Rep']['count'] += 1
elif d_1000 <= 430:
counts['Res']['count'] += 1
elif d_1000 <= 930:
counts['Sta']['count'] += 1
elif d_1000 <= 980:
counts['All']['count'] += 1
elif d_1000 <= 990:
counts['MVP']['count'] += 1
else:
counts['HoF']['count'] += 1
elif pack['pack_type']['name'] == 'Premium':
# Card 1
d_1000 = random.randint(1, 1000)
if d_1000 <= 400:
counts['Rep']['count'] += 1
elif d_1000 <= 870:
counts['Res']['count'] += 1
elif d_1000 <= 970:
counts['Sta']['count'] += 1
elif d_1000 <= 990:
counts['All']['count'] += 1
else:
counts['MVP']['count'] += 1
# Card 2
d_1000 = random.randint(1, 1000)
if d_1000 <= 300:
counts['Rep']['count'] += 1
elif d_1000 <= 770:
counts['Res']['count'] += 1
elif d_1000 <= 970:
counts['Sta']['count'] += 1
elif d_1000 <= 990:
counts['All']['count'] += 1
else:
counts['MVP']['count'] += 1
# Card 3
d_1000 = random.randint(1, 1000)
if d_1000 <= 200:
counts['Rep']['count'] += 1
elif d_1000 <= 640:
counts['Res']['count'] += 1
elif d_1000 <= 940:
counts['Sta']['count'] += 1
elif d_1000 <= 990:
counts['All']['count'] += 1
else:
counts['MVP']['count'] += 1
# Card 4
d_1000 = random.randint(1, 1000)
if d_1000 <= 100:
counts['Rep']['count'] += 1
if d_1000 <= 530:
counts['Res']['count'] += 1
elif d_1000 <= 930:
counts['Sta']['count'] += 1
elif d_1000 <= 980:
counts['All']['count'] += 1
elif d_1000 <= 990:
counts['MVP']['count'] += 1
else:
counts['HoF']['count'] += 1
# Card 5
d_1000 = random.randint(1, 1000)
if d_1000 <= 380:
counts['Res']['count'] += 1
elif d_1000 <= 880:
counts['Sta']['count'] += 1
elif d_1000 <= 980:
counts['All']['count'] += 1
elif d_1000 <= 990:
counts['MVP']['count'] += 1
else:
counts['HoF']['count'] += 1
elif pack['pack_type']['name'] == 'Check-In Player':
logger.info(f'Building Check-In Pack // extra_val (type): {extra_val} {type(extra_val)}')
# Single Card
mod = 0
if isinstance(extra_val, int):
mod = extra_val
d_1000 = random.randint(1, 1000 + mod)
if d_1000 >= 1100:
counts['All']['count'] += 1
elif d_1000 >= 1000:
counts['Sta']['count'] += 1
elif d_1000 >= 500:
counts['Res']['count'] += 1
else:
counts['Rep']['count'] += 1
else:
raise TypeError(f'Pack type not recognized: {pack["pack_type"]["name"]}')
pull_notifs = []
for key in counts:
mvp_flag = None
if counts[key]['count'] > 0:
params = [
('min_rarity', counts[key]['rarity']), ('max_rarity', counts[key]['rarity']),
('limit', counts[key]['count'])
]
if all_packs[0]['pack_team'] is not None:
params.extend([('franchise', all_packs[0]['pack_team']['lname']), ('in_packs', True)])
elif all_packs[0]['pack_cardset'] is not None:
params.append(('cardset_id', all_packs[0]['pack_cardset']['id']))
else:
params.append(('in_packs', True))
pl = await db_get('players/random', params=params)
if pl['count'] != counts[key]['count']:
mvp_flag = counts[key]['count'] - pl['count']
logging.info(f'Set mvp flag to {mvp_flag} / cardset_id: {all_packs[0]["pack_cardset"]["id"]}')
for x in pl['players']:
this_pack_players.append(x)
all_players.append(x)
if x['rarity']['value'] >= 3:
pull_notifs.append(x)
if mvp_flag and all_packs[0]['pack_cardset']['id'] not in [23]:
logging.info(f'Adding {mvp_flag} MVPs for missing cards')
pl = await db_get('players/random', params=[('min_rarity', 5), ('limit', mvp_flag)])
for x in pl['players']:
this_pack_players.append(x)
all_players.append(x)
# Add dupes of Replacement/Reserve cards
elif mvp_flag:
logging.info(f'Adding {mvp_flag} duplicate pokemon cards')
for count in range(mvp_flag):
logging.info(f'Adding {pl["players"][0]["p_name"]} to the pack')
this_pack_players.append(x)
all_players.append(pl['players'][0])
success = await db_post(
'cards',
payload={'cards': [{
'player_id': x['player_id'], 'team_id': pack['team']['id'], 'pack_id': pack['id']} for x in this_pack_players]
},
timeout=10
)
if not success:
raise ConnectionError(f'Failed to create this pack of cards.')
await db_patch('packs', object_id=pack['id'], params=[
('open_time', int(datetime.datetime.timestamp(datetime.datetime.now())*1000))
])
pack_ids.append(pack['id'])
for pull in pull_notifs:
logger.info(f'good pull: {pull}')
await db_post('notifs', payload={
'created': int(datetime.datetime.timestamp(datetime.datetime.now())*1000),
'title': 'Rare Pull',
'field_name': f'{player_desc(pull)} ({pull["rarity"]["name"]})',
'message': f'Pulled by {team["abbrev"]}',
'about': f'Player-{pull["player_id"]}'
})
return pack_ids
async def give_packs(team: dict, num_packs: int, pack_type: dict = None) -> dict:
"""
Parameters
----------
pack_type
team
num_packs
Returns
-------
{ 'count': int, 'packs': [ all team packs ] }
"""
pt_id = pack_type['id'] if pack_type is not None else 1
await db_post(
'packs',
payload={'packs': [{'team_id': team['id'], 'pack_type_id': pt_id} for x in range(num_packs)]}
)
total_packs = await db_get('packs', params=[
('team_id', team['id']), ('opened', False)
])
return total_packs
def get_sheets(bot):
try:
return bot.get_cog('Players').sheets
except Exception as e:
logger.error(f'Could not grab sheets auth: {e}')
raise ConnectionError(f'Bot has not authenticated with discord; please try again in 1 minute.')
def create_team_sheet(team, email: str, current, bot):
sheets = get_sheets(bot)
new_sheet = sheets.drive.copy_file(
f'{current["gsheet_template"]}',
f'{team["lname"]} Roster Sheet v{current["gsheet_version"]}',
'1539D0imTMjlUx2VF3NPMt7Sv85sb2XAJ'
)
logger.info(f'new_sheet: {new_sheet}')
this_sheet = sheets.open_by_key(new_sheet['id'])
this_sheet.share(email, role='writer')
team_data = this_sheet.worksheet_by_title('Team Data')
team_data.update_values(
crange='B1:B2',
values=[[f'{team["id"]}'], [f'\'{team_hash(team)}']]
)
logger.debug(f'this_sheet: {this_sheet}')
return this_sheet
async def refresh_sheet(team, bot, sheets=None) -> None:
return
if not sheets:
sheets = get_sheets(bot)
this_sheet = sheets.open_by_key(team['gsheet'])
my_cards = this_sheet.worksheet_by_title('My Cards')
all_cards = this_sheet.worksheet_by_title('All Cards')
my_cards.update_value('A2', 'FALSE')
all_cards.update_value('A2', 'FALSE')
await asyncio.sleep(1)
my_cards.update_value('A2', 'TRUE')
await asyncio.sleep(0.5)
all_cards.update_value('A2', 'TRUE')
def delete_sheet(team, bot):
sheets = get_sheets(bot)
this_sheet = sheets.open_by_key(team['gsheet'])
this_sheet.delete()
def share_sheet(team, email, bot) -> None:
sheets = get_sheets(bot)
this_sheet = sheets.open_by_key(team['gsheet'])
this_sheet.share(email, role='writer')
def int_timestamp(datetime_obj: datetime.datetime) -> int:
return int(datetime.datetime.timestamp(datetime_obj) * 1000)
def get_pos_abbrev(pos_name):
if pos_name == 'Catcher':
return 'C'
elif pos_name == 'First Base':
return '1B'
elif pos_name == 'Second Base':
return '2B'
elif pos_name == 'Third Base':
return '3B'
elif pos_name == 'Shortstop':
return 'SS'
elif pos_name == 'Left Field':
return 'LF'
elif pos_name == 'Center Field':
return 'CF'
elif pos_name == 'Right Field':
return 'RF'
elif pos_name == 'Pitcher':
return 'P'
elif pos_name == 'Designated Hitter':
return 'DH'
elif pos_name == 'Pinch Hitter':
return 'PH'
else:
raise KeyError(f'{pos_name} is not a recognized position name')
async def cardset_search(cardset: str, cardset_list: list) -> Optional[dict]:
cardset_name = fuzzy_search(cardset, cardset_list)
if not cardset_name:
return None
c_query = await db_get('cardsets', params=[('name', cardset_name)])
if c_query['count'] == 0:
return None
return c_query['cardsets'][0]
def get_blank_team_card(player):
return {'player': player, 'team': {'lname': 'Paper Dynasty', 'logo': IMAGES['logo'], 'season': PD_SEASON}}
def get_rosters(team, bot, roster_num: Optional[int] = None) -> list:
sheets = get_sheets(bot)
this_sheet = sheets.open_by_key(team['gsheet'])
r_sheet = this_sheet.worksheet_by_title(f'My Rosters')
logger.debug(f'this_sheet: {this_sheet} / r_sheet = {r_sheet}')
all_rosters = [None, None, None]
# Pull roster 1
if not roster_num or roster_num == 1:
roster_1 = r_sheet.range('B3:B28')
roster_name = r_sheet.cell('F30').value
logger.info(f'roster_1: {roster_1}')
if not roster_1[0][0].value == '':
all_rosters[0] = {'name': roster_name, 'roster_num': 1, 'team_id': team['id'], 'cards': None}
all_rosters[0]['cards'] = [int(x[0].value) for x in roster_1]
# Pull roster 2
if not roster_num or roster_num == 2:
roster_2 = r_sheet.range('B29:B54')
roster_name = r_sheet.cell('F31').value
logger.info(f'roster_2: {roster_2}')
if not roster_2[0][0].value == '':
all_rosters[1] = {'name': roster_name, 'roster_num': 2, 'team_id': team['id'], 'cards': None}
all_rosters[1]['cards'] = [int(x[0].value) for x in roster_2]
# Pull roster 3
if not roster_num or roster_num == 3:
roster_3 = r_sheet.range('B55:B80')
roster_name = r_sheet.cell('F32').value
logger.info(f'roster_3: {roster_3}')
if not roster_3[0][0].value == '':
all_rosters[2] = {'name': roster_name, 'roster_num': 3, 'team_id': team['id'], 'cards': None}
all_rosters[2]['cards'] = [int(x[0].value) for x in roster_3]
return all_rosters
def get_roster_lineups(team, bot, roster_num, lineup_num) -> list:
sheets = get_sheets(bot)
logger.debug(f'sheets: {sheets}')
this_sheet = sheets.open_by_key(team['gsheet'])
logger.debug(f'this_sheet: {this_sheet}')
r_sheet = this_sheet.worksheet_by_title('My Rosters')
logger.debug(f'r_sheet: {r_sheet}')
if lineup_num == 1:
row_start = 9
row_end = 17
else:
row_start = 18
row_end = 26
if roster_num == 1:
l_range = f'H{row_start}:I{row_end}'
elif roster_num == 2:
l_range = f'J{row_start}:K{row_end}'
else:
l_range = f'L{row_start}:M{row_end}'
logger.debug(f'l_range: {l_range}')
raw_cells = r_sheet.range(l_range)
logger.debug(f'raw_cells: {raw_cells}')
try:
lineup_cells = [(row[0].value, int(row[1].value)) for row in raw_cells]
except ValueError as e:
logger.error(f'Could not pull roster for {team["abbrev"]} due to a ValueError')
raise ValueError(f'Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to '
f'get the card IDs')
logger.debug(f'lineup_cells: {lineup_cells}')
return lineup_cells
def post_ratings_guide(team, bot, this_sheet=None):
if not this_sheet:
sheets = get_sheets(bot)
this_sheet = sheets.open_by_key(team['gsheet'])
p_guide = this_sheet.worksheet_by_title('Full Guide - Pitchers')
b_guide = this_sheet.worksheet_by_title('Full Guide - Batters')
p_guide.update_value('A1', RATINGS_PITCHER_FORMULA)
b_guide.update_value('A1', RATINGS_BATTER_FORMULA)
async def legal_channel(ctx):
bad_channels = ['paper-dynasty-chat', 'pd-news-ticker', 'pd-network-news']
if isinstance(ctx, commands.Context):
if ctx.channel.name in bad_channels:
raise commands.CheckFailure(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)')
else:
return True
elif ctx.channel.name in bad_channels:
# await ctx.message.add_reaction('❌')
# await ctx.send(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)')
# logger.warning(f'{ctx.author.name} posted in illegal channel.')
# return False
raise discord.app_commands.AppCommandError(f'Slide on down to the {get_channel(ctx, "pd-bot-hole").mention} ;)')
else:
return True
def owner_only(interaction: discord.Interaction):
if interaction.user.id == 258104532423147520:
return True
else:
return False
def get_role(ctx, role_name):
return discord.utils.get(ctx.guild.roles, name=role_name)
async def team_summary_embed(team, ctx, include_roster: bool = True):
embed = get_team_embed(f'{team["lname"]} Overview', team)
embed.add_field(name='General Manager', value=team['gmname'], inline=False)
embed.add_field(name='Wallet', value=f'{team["wallet"]}')
# embed.add_field(name='Collection Value', value=team['collection_value'])
p_query = await db_get('packs', params=[('team_id', team['id']), ('opened', False)])
if p_query['count'] > 0:
all_packs = {}
for x in p_query['packs']:
if x['pack_type']['name'] not in all_packs:
all_packs[x['pack_type']['name']] = 1
else:
all_packs[x['pack_type']['name']] += 1
pack_string = ''
for pack_type in all_packs:
pack_string += f'{pack_type.title()}: {all_packs[pack_type]}\n'
else:
pack_string = 'None'
embed.add_field(name='Unopened Packs', value=pack_string)
embed.add_field(name='Team Rating', value=f'{team["ranking"]}')
r_query = await db_get(f'results/team/{team["id"]}?season={PD_SEASON}')
if r_query:
embed.add_field(
name='Record',
value=f'Ranked: {r_query["ranked_wins"]}-{r_query["ranked_losses"]}\n'
f'Unlimited: {r_query["casual_wins"]}-{r_query["casual_losses"]}'
)
# try:
# r_query = await db_get('rosters', params=[('team_id', team['id'])])
# if r_query['count']:
# embed.add_field(name=f'Rosters', value=f'** **', inline=False)
# for roster in r_query['rosters']:
# roster_string = ''
# for i in range(1, 27):
# card = roster[f'card_{i}']
# roster_string += f'{card["player"]["description"]} ({card["player"]["pos_1"]})\n'
# embed.add_field(
# name=f'{roster["name"]} Roster',
# value=roster_string if len(roster_string) else "Unknown"
# )
# else:
# embed.add_field(
# name='Rosters',
# value='You can set up to three rosters for quick switching from your team sheet.',
# inline=False
# )
# except Exception as e:
# logger.error(f'Could not pull rosters for {team["abbrev"]}')
# embed.add_field(
# name='Rosters',
# value='Unable to pull current rosters. `/pullroster` to sync.',
# inline=False
# )
if include_roster:
embed.add_field(name='Team Sheet', value=get_roster_sheet(team, allow_embed=True), inline=False)
embed.add_field(
name='For Help',
value=f'`/help-pd` has FAQs; feel free to post questions in '
f'{get_channel(ctx, "paper-dynasty-chat").mention}.',
inline=False
)
return embed
async def give_cards_to_team(team, players: list = None, player_ids: list = None, pack_id=None):
if not pack_id:
p_query = await db_post(
'packs/one',
payload={
'team_id': team['id'],
'pack_type_id': 4,
'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000}
)
pack_id = p_query['id']
if not players and not player_ids:
raise ValueError('One of players or player_ids must be provided to distribute cards')
if players:
await db_post('cards', payload={'cards': [
{'player_id': x['player_id'], 'team_id': team['id'], 'pack_id': pack_id} for x in players
]}, timeout=10)
elif player_ids:
await db_post('cards', payload={'cards': [
{'player_id': x, 'team_id': team['id'], 'pack_id': pack_id} for x in player_ids
]}, timeout=10)
def get_ratings_guide(sheets):
this_sheet = sheets.open_by_key(RATINGS_SHEET_KEY)
b_sheet = this_sheet.worksheet_by_title('ratings_Batters')
p_sheet = this_sheet.worksheet_by_title('ratings_Pitchers')
b_data = b_sheet.range('A2:N')
p_data = p_sheet.range('A2:N')
try:
batters = [
{
'player_id': int(x[0].value),
'p_name': x[1].value,
'rating': int(x[2].value),
'contact-r': int(x[3].value),
'contact-l': int(x[4].value),
'power-r': int(x[5].value),
'power-l': int(x[6].value),
'vision': int(x[7].value),
'speed': int(x[8].value),
'stealing': int(x[9].value),
'reaction': int(x[10].value),
'arm': int(x[11].value),
'fielding': int(x[12].value),
'hand': int(x[13].value),
} for x in b_data
]
pitchers = [
{
'player_id': int(x[0].value),
'p_name': x[1].value,
'rating': int(x[2].value),
'control-r': int(x[3].value),
'control-l': int(x[4].value),
'stuff-r': int(x[5].value),
'stuff-l': int(x[6].value),
'stamina': int(x[7].value),
'fielding': int(x[8].value),
'hit-9': int(x[9].value),
'k-9': int(x[10].value),
'bb-9': int(x[11].value),
'hr-9': int(x[12].value),
'hand': int(x[13].value),
} for x in p_data
]
except Exception as e:
return {'valid': False}
return {
'valid': True,
'batter_ratings': batters,
'pitcher_ratings': pitchers
}
async def paperdex_cardset_embed(team: dict, this_cardset: dict) -> list[discord.Embed]:
all_dex = await db_get(
'paperdex',
params=[('team_id', team['id']), ('cardset_id', this_cardset['id']), ('flat', True)]
)
dex_player_list = [x['player'] for x in all_dex['paperdex']]
hof_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
mvp_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
as_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
sta_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
res_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
rep_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
coll_data = {
99: {
'name': 'Hall of Fame',
'owned': 0,
'players': [],
'embeds': [hof_embed]
},
1: {
'name': 'MVP',
'owned': 0,
'players': [],
'embeds': [mvp_embed]
},
2: {
'name': 'All-Star',
'owned': 0,
'players': [],
'embeds': [as_embed]
},
3: {
'name': 'Starter',
'owned': 0,
'players': [],
'embeds': [sta_embed]
},
4: {
'name': 'Reserve',
'owned': 0,
'players': [],
'embeds': [res_embed]
},
5: {
'name': 'Replacement',
'owned': 0,
'players': [],
'embeds': [rep_embed]
},
'total_owned': 0
}
set_players = await db_get(
'players',
params=[('cardset_id', this_cardset['id']), ('flat', True), ('inc_dex', False)],
timeout=5
)
for player in set_players['players']:
if player['player_id'] in dex_player_list:
coll_data[player['rarity']]['owned'] += 1
coll_data['total_owned'] += 1
player['owned'] = True
else:
player['owned'] = False
logger.debug(f'player: {player} / type: {type(player)}')
coll_data[player['rarity']]['players'].append(player)
cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
cover_embed.description = this_cardset['name']
cover_embed.add_field(name='# Total Cards', value=f'{set_players["count"]}')
cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}')
display_embeds = [cover_embed]
for rarity_id in coll_data:
if rarity_id != 'total_owned':
if coll_data[rarity_id]['players']:
coll_data[rarity_id]['embeds'][0].description = f'Rarity: {coll_data[rarity_id]["name"]}'
coll_data[rarity_id]['embeds'][0].add_field(
name='# Collected / # Total Cards',
value=f'{coll_data[rarity_id]["owned"]} / {len(coll_data[rarity_id]["players"])}',
inline=False
)
chunk_string = ''
for index, this_player in enumerate(coll_data[rarity_id]['players']):
logger.debug(f'this_player: {this_player}')
chunk_string += '' if this_player['owned'] else ''
chunk_string += f'{this_player["p_name"]}\n'
if (index + 1) == len(coll_data[rarity_id]["players"]):
coll_data[rarity_id]['embeds'][0].add_field(
name=f'Group {math.ceil((index + 1) / 20)} / '
f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}',
value=chunk_string
)
elif (index + 1) % 20 == 0:
coll_data[rarity_id]['embeds'][0].add_field(
name=f'Group {math.floor((index + 1) / 20)} / '
f'{math.ceil(len(coll_data[rarity_id]["players"]) / 20)}',
value=chunk_string
)
chunk_string = ''
display_embeds.append(coll_data[rarity_id]['embeds'][0])
return display_embeds
async def paperdex_team_embed(team: dict, mlb_team: dict) -> list[discord.Embed]:
all_dex = await db_get(
'paperdex',
params=[('team_id', team['id']), ('franchise', mlb_team['lname']), ('flat', True)]
)
dex_player_list = [x['player'] for x in all_dex['paperdex']]
c_query = await db_get('cardsets')
coll_data = {'total_owned': 0}
total_players = 0
for x in c_query['cardsets']:
set_players = await db_get(
'players',
params=[('cardset_id', x['id']), ('franchise', mlb_team['lname']), ('flat', True), ('inc_dex', False)]
)
if set_players is not None:
coll_data[x['id']] = {
'name': x['name'],
'owned': 0,
'players': [],
'embeds': [get_team_embed(f'{team["lname"]} Collection', team=team)]
}
total_players += set_players['count']
for player in set_players['players']:
if player['player_id'] in dex_player_list:
coll_data[x['id']]['owned'] += 1
coll_data['total_owned'] += 1
player['owned'] = True
else:
player['owned'] = False
logger.debug(f'player: {player} / type: {type(player)}')
coll_data[x['id']]['players'].append(player)
cover_embed = get_team_embed(f'{team["lname"]} Collection', team=team)
cover_embed.description = mlb_team['lname']
cover_embed.add_field(name='# Total Cards', value=f'{total_players}')
cover_embed.add_field(name='# Collected', value=f'{coll_data["total_owned"]}')
display_embeds = [cover_embed]
for cardset_id in coll_data:
if cardset_id != 'total_owned':
if coll_data[cardset_id]['players']:
coll_data[cardset_id]['embeds'][0].description = f'{mlb_team["lname"]} / ' \
f'{coll_data[cardset_id]["name"]}'
coll_data[cardset_id]['embeds'][0].add_field(
name='# Collected / # Total Cards',
value=f'{coll_data[cardset_id]["owned"]} / {len(coll_data[cardset_id]["players"])}',
inline=False
)
chunk_string = ''
for index, this_player in enumerate(coll_data[cardset_id]['players']):
logger.debug(f'this_player: {this_player}')
chunk_string += '' if this_player['owned'] else ''
chunk_string += f'{this_player["p_name"]}\n'
if (index + 1) == len(coll_data[cardset_id]["players"]):
coll_data[cardset_id]['embeds'][0].add_field(
name=f'Group {math.ceil((index + 1) / 20)} / '
f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}',
value=chunk_string
)
elif (index + 1) % 20 == 0:
coll_data[cardset_id]['embeds'][0].add_field(
name=f'Group {math.floor((index + 1) / 20)} / '
f'{math.ceil(len(coll_data[cardset_id]["players"]) / 20)}',
value=chunk_string
)
chunk_string = ''
display_embeds.append(coll_data[cardset_id]['embeds'][0])
return display_embeds
def get_pack_cover(pack):
if pack['pack_cardset'] is not None and pack['pack_cardset'] == 23:
return IMAGES['pack-pkmnbs']
elif pack['pack_type']['name'] in ['Premium', 'MVP']:
return IMAGES['pack-pre']
elif pack['pack_type']['name'] == 'Standard':
return IMAGES['pack-sta']
elif pack['pack_type']['name'] == 'Mario':
return IMAGES['pack-mar']
else:
return None
async def open_st_pr_packs(all_packs: list, team: dict, context):
pack_channel = get_channel(context, 'pack-openings')
pack_cover = get_pack_cover(all_packs[0])
if pack_cover is None:
pack_channel = context.channel
if not pack_channel:
raise ValueError(f'I cannot find the pack-openings channel. {get_cal_user(context).mention} - halp?')
pack_ids = await roll_for_cards(all_packs)
if not pack_ids:
logger.error(f'open_packs - unable to roll_for_cards for packs: {all_packs}')
raise ValueError(f'I was not able to unpack these cards')
all_cards = []
for p_id in pack_ids:
new_cards = await db_get('cards', params=[('pack_id', p_id)])
all_cards.extend(new_cards['cards'])
if not all_cards:
logger.error(f'open_packs - unable to get cards for packs: {pack_ids}')
raise ValueError(f'I was not able to display these cards')
# Present cards to opening channel
if type(context) == commands.Context:
author = context.author
else:
author = context.user
await context.channel.send(content=f'Let\'s head down to {pack_channel.mention}!')
await display_cards(all_cards, team, pack_channel, author, pack_cover=pack_cover)
async def get_choice_from_cards(
interaction: discord.Interaction, all_players: list = None, cover_title: str = None,
cover_desc: str = None, cover_image_url: str = None, callback=None, temp_message: str = None,
conf_message: str = None, delete_message: bool = False):
# Display them with pagination, prev/next/select
card_embeds = [
await get_card_embeds(
{'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}}
) for x in all_players
]
logger.debug(f'card embeds: {card_embeds}')
if cover_title is not None and cover_image_url is not None:
page_num = 0
view = Pagination([interaction.user], timeout=30)
view.left_button.disabled = True
view.left_button.label = f'Prev: -/{len(card_embeds)}'
view.cancel_button.label = f'Take This Card'
view.cancel_button.style = discord.ButtonStyle.success
view.cancel_button.disabled = True
view.right_button.label = f'Next: 1/{len(card_embeds)}'
msg = await interaction.channel.send(
content=None,
embed=image_embed(
image_url=cover_image_url,
title=cover_title,
desc=cover_desc
),
view=view
)
else:
page_num = 1
view = Pagination([interaction.user], timeout=30)
view.left_button.label = f'Prev: -/{len(card_embeds)}'
view.left_button.disabled = True
view.cancel_button.label = f'Take This Card'
view.cancel_button.style = discord.ButtonStyle.success
view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}'
msg = await interaction.channel.send(content=None, embeds=card_embeds[page_num - 1], view=view)
if temp_message is not None:
temp_msg = await interaction.channel.send(content=temp_message)
else:
temp_msg = None
while True:
await view.wait()
if view.value:
if view.value == 'cancel':
await msg.edit(view=None)
if callback is not None:
callback(all_players[page_num - 1])
if conf_message is not None:
if temp_msg is not None:
await temp_msg.edit(content=conf_message)
else:
await interaction.channel.send(content=conf_message)
break
if view.value == 'left':
page_num -= 1 if page_num > 1 else len(card_embeds)
if view.value == 'right':
page_num += 1 if page_num < len(card_embeds) else 1
else:
if page_num == len(card_embeds):
page_num = 1
else:
page_num += 1
view.value = None
view = Pagination([interaction.user], timeout=30)
view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}'
view.cancel_button.label = f'Take This Card'
view.cancel_button.style = discord.ButtonStyle.success
view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}'
if page_num == 1:
view.left_button.label = f'Prev: -/{len(card_embeds)}'
view.left_button.disabled = True
elif page_num == len(card_embeds):
view.right_button.label = f'Next: -/{len(card_embeds)}'
view.right_button.disabled = True
await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view)
if delete_message:
await msg.delete()
return all_players[page_num - 1]
async def open_choice_pack(this_pack, team: dict, context, cardset_id: Optional[int] = None):
pack_channel = get_channel(context, 'pack-openings')
pack_cover = get_pack_cover(this_pack)
pack_type = this_pack['pack_type']['name']
players = []
if pack_type == 'Mario':
d1000 = random.randint(1, 1000)
if d1000 > 800:
rarity_id = 5
elif d1000 > 550:
rarity_id = 3
else:
rarity_id = 2
pl = await db_get(
'players/random',
params=[
('cardset_id', 8), ('min_rarity', rarity_id), ('max_rarity', rarity_id), ('limit', 4)
]
)
players = pl['players']
elif pack_type == 'Team Choice':
if this_pack['pack_team'] is None:
raise KeyError(f'Team not listed for Team Choice pack')
d1000 = random.randint(1, 1000)
pack_cover = this_pack['pack_team']['logo']
if d1000 > 800:
rarity_id = 5
pack_cover = IMAGES['mvp'][this_pack['pack_team']['lname']]
elif d1000 > 550:
rarity_id = 3
else:
rarity_id = 2
# # HAX FOR SOCC TO GET HIS MVP PACK
# if (team['abbrev'] in ['KSK', 'NJY']) and (datetime.datetime.today().day == 24):
# rarity_id = 5
min_rarity = rarity_id
while len(players) < 4 and rarity_id < 10:
params = [
('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4 - len(players)),
('franchise', this_pack['pack_team']['lname'])
]
if this_pack['pack_team']['abbrev'] not in ['MSS']:
params.append(('in_packs', True))
if cardset_id is not None:
params.append(('cardset_id', cardset_id))
pl = await db_get(
'players/random',
params=params
)
if pl['count'] >= 0:
for x in pl['players']:
if x not in players:
players.append(x)
if len(players) < 4:
min_rarity += 1
rarity_id += 1
elif pack_type == 'Promo Choice':
if this_pack['pack_cardset'] is None:
raise KeyError(f'Cardset not listed for Promo Choice pack')
d1000 = random.randint(1, 1000)
pack_cover = IMAGES['mvp-hype']
cardset_id = this_pack['pack_cardset']['id']
rarity_id = 5
if d1000 > 800:
rarity_id = 8
while len(players) < 4 and rarity_id < 10:
pl = await db_get(
'players/random',
params=[('cardset_id', cardset_id), ('min_rarity', rarity_id), ('max_rarity', rarity_id),
('limit', 8)]
)
if pl['count'] >= 0:
for x in pl['players']:
if len(players) >= 4:
break
if x not in players:
players.append(x)
if len(players) < 4:
cardset_id = LIVE_CARDSET_ID
else:
# Get 4 MVP cards
rarity_id = 5
if pack_type == 'HoF':
rarity_id = 8
elif pack_type == 'All Star':
rarity_id = 3
min_rarity = rarity_id
while len(players) < 4 and rarity_id < 10:
params = [
('min_rarity', min_rarity), ('max_rarity', rarity_id), ('limit', 4), ('in_packs', True)
]
if this_pack['pack_team'] is not None:
params.append(('franchise', this_pack['pack_team']['lname']))
if cardset_id is not None:
params.append(('cardset_id', cardset_id))
pl = await db_get('players/random', params=params)
if pl['count'] > 0:
players.extend(pl['players'])
if len(players) < 4:
rarity_id += 3
if len(players) == 0:
logger.error(f'Could not create choice pack')
raise ConnectionError(f'Could not create choice pack')
if type(context) == commands.Context:
author = context.author
else:
author = context.user
logger.info(f'helpers - open_choice_pack - players: {players}')
# Display them with pagination, prev/next/select
card_embeds = [
await get_card_embeds(
# {'player': x, 'team': {'lname': 'Paper Dynasty', 'season': PD_SEASON, 'logo': IMAGES['logo']}}
{'player': x, 'team': team} # Show team and dupe info
) for x in players
]
logger.debug(f'card embeds: {card_embeds}')
page_num = 0
view = Pagination([author], timeout=30)
view.left_button.disabled = True
view.left_button.label = f'Prev: -/{len(card_embeds)}'
view.cancel_button.label = f'Take This Card'
view.cancel_button.style = discord.ButtonStyle.success
view.cancel_button.disabled = True
view.right_button.label = f'Next: 1/{len(card_embeds)}'
# React to selection
await context.channel.send(f'Let\'s head down to {pack_channel.mention}!')
msg = await pack_channel.send(
content=None,
embed=image_embed(pack_cover, title=f'{team["lname"]}', desc=f'{pack_type} Pack - Choose 1 of 4 {pack_type}s!'),
view=view
)
if rarity_id >= 5:
tmp_msg = await pack_channel.send(content=f'<@&1163537676885033010> we\'ve got an MVP!')
else:
tmp_msg = await pack_channel.send(content=f'We\'ve got a choice pack here!')
while True:
await view.wait()
if view.value:
if view.value == 'cancel':
await msg.edit(view=None)
try:
await give_cards_to_team(team, players=[players[page_num - 1]], pack_id=this_pack['id'])
except Exception as e:
logger.error(f'failed to create cards: {e}')
raise ConnectionError(f'Failed to distribute these cards.')
await db_patch('packs', object_id=this_pack['id'], params=[
('open_time', int(datetime.datetime.timestamp(datetime.datetime.now()) * 1000))
])
await tmp_msg.edit(
content=f'{players[page_num - 1]["p_name"]} has been added to the '
f'**{team["sname"]}** binder!'
)
break
if view.value == 'left':
page_num -= 1 if page_num > 1 else len(card_embeds)
if view.value == 'right':
page_num += 1 if page_num < len(card_embeds) else 1
else:
if page_num == len(card_embeds):
page_num = 1
else:
page_num += 1
view.value = None
view = Pagination([author], timeout=30)
view.left_button.label = f'Prev: {page_num - 1}/{len(card_embeds)}'
view.cancel_button.label = f'Take This Card'
view.cancel_button.style = discord.ButtonStyle.success
view.right_button.label = f'Next: {page_num + 1}/{len(card_embeds)}'
if page_num == 1:
view.left_button.label = f'Prev: -/{len(card_embeds)}'
view.left_button.disabled = True
elif page_num == len(card_embeds):
view.right_button.label = f'Next: -/{len(card_embeds)}'
view.right_button.disabled = True
await msg.edit(content=None, embeds=card_embeds[page_num - 1], view=view)
async def confirm_pack_purchase(interaction, owner_team, num_packs, total_cost, pack_embed):
view = Confirm(responders=[interaction.user], timeout=30)
await interaction.channel.send(
content=None,
embed=pack_embed
)
question = await interaction.channel.send(
content=f'Your Wallet: {owner_team["wallet"]}\n'
f'Pack{"s" if num_packs > 1 else ""} Price: {total_cost}\n'
f'After Purchase: {owner_team["wallet"] - total_cost}\n\n'
f'Would you like to make this purchase?',
view=view
)
await view.wait()
if not view.value:
await question.edit(
content='Saving that money. Smart.',
view=None
)
return None
else:
return question
def player_desc(this_player) -> str:
if this_player['p_name'] in this_player['description']:
return this_player['description']
return f'{this_player["description"]} {this_player["p_name"]}'
def player_pcard(this_player):
if this_player['image'] is not None and 'pitching' in this_player['image']:
return this_player['image']
elif this_player['image2'] is not None and 'pitching' in this_player['image2']:
return this_player['image2']
else:
return this_player['image']
def player_bcard(this_player):
if this_player['image'] is not None and 'batting' in this_player['image']:
return this_player['image']
elif this_player['image2'] is not None and 'batting' in this_player['image2']:
return this_player['image2']
# elif this_player['image'] is not None and 'pitching' in this_player['image']:
# return PITCHER_BATTING_CARD
else:
return this_player['image']
def random_gif(search_term: str):
req_url = f'https://api.giphy.com/v1/gifs/translate?s={search_term}&api_key=H86xibttEuUcslgmMM6uu74IgLEZ7UOD'
resp = requests.get(req_url, timeout=3)
if resp.status_code == 200:
data = resp.json()
if 'trump' in data['data']['title']:
return random_conf_gif()
else:
return data['data']['url']
else:
logger.warning(resp.text)
raise ValueError(f'DB: {resp.text}')
def random_from_list(data_list: list):
item = data_list[random.randint(0, len(data_list) - 1)]
logger.info(f'random_from_list: {item}')
return item
def user_has_role(user: discord.User | discord.Member, role_name: str) -> bool:
for x in user.roles:
if x.name == role_name:
return True
return False
def random_insult() -> str:
return random_from_list(INSULTS)