Added Brilliant Stars gauntlet

This commit is contained in:
Cal Corum 2024-12-24 00:22:30 -06:00
parent d7a766029e
commit 5f8a422c2c
8 changed files with 1077 additions and 469 deletions

View File

@ -3,6 +3,7 @@ import json
import db_calls import db_calls
import db_calls_gameplay import db_calls_gameplay
from gauntlets import evolve_pokemon
from helpers import * from helpers import *
from db_calls import * from db_calls import *
from discord import Member from discord import Member
@ -585,5 +586,12 @@ class Admins(commands.Cog):
await ctx.send(f'Here is your dropdown:', view=view) await ctx.send(f'Here is your dropdown:', view=view)
@commands.command(name='test_evo', help='Mod: Test pokemon evolution')
@commands.is_owner()
async def test_evolution(self, ctx, team_abbrev: str):
this_team = await get_team_by_abbrev(team_abbrev)
await evolve_pokemon(this_team, ctx.channel)
async def setup(bot): async def setup(bot):
await bot.add_cog(Admins(bot)) await bot.add_cog(Admins(bot))

View File

@ -2420,392 +2420,6 @@ class Gameplay(commands.Cog):
f'{get_channel(interaction, "pd-news-ticker").mention}!' f'{get_channel(interaction, "pd-news-ticker").mention}!'
) )
"""
END OF THE NEW GAME END
"""
# away_team = await db_get('teams', object_id=this_game.away_team_id)
# home_team = await db_get('teams', object_id=this_game.home_team_id)
#
# away_stats = {
# # 'p_lines': get_pitching_stats(this_game.id, team_id=away_team['id']),
# 'p_lines': [],
# 'b_lines': get_batting_stats(this_game.id, team_id=away_team['id']),
# 'f_lines': get_fielding_stats(this_game.id, team_id=away_team['id'])
# }
# home_stats = {
# # 'p_lines': get_pitching_stats(this_game.id, team_id=home_team['id']),
# 'p_lines': [],
# 'b_lines': get_batting_stats(this_game.id, team_id=home_team['id']),
# 'f_lines': get_fielding_stats(this_game.id, team_id=home_team['id']),
# # 'score': away_stats['p_lines'][0]['tm_runs']
# }
#
# logging.debug(f'away_stats: {away_stats}\n\nhome_stats: {home_stats}')
#
# away_pitchers = await get_team_lineups(
# this_game.id, team_id=away_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
# )
# for line in away_pitchers:
# try:
# # logging.info(f'line: {line}')
# this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
# # logging.info(f'away / this_stats: {this_stats}')
# away_stats['p_lines'].extend(this_stats)
# if 'score' not in home_stats:
# # logging.info(f'score not in home_stats')
# home_stats['score'] = this_stats[0]['pl_runs']
# else:
# # logging.info(f'score is in home_stats')
# home_stats['score'] += this_stats[0]['pl_runs']
# if 'hits' not in home_stats:
# # logging.info(f'hits not in home_stats')
# home_stats['hits'] = this_stats[0]['pl_hit']
# else:
# # logging.info(f'hits is in home_stats')
# home_stats['hits'] += this_stats[0]['pl_hit']
# except Exception as e:
# bad_player = await get_player(this_game, line)
# logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: '
# f'{type(e)}: {e}')
# await interaction.edit_original_response(
# content=f'I was not able to process stats for {bad_player["name"]} - '
# f'{get_cal_user(interaction).mention} help!')
#
# home_pitchers = await get_team_lineups(
# this_game.id, team_id=home_team['id'], inc_inactive=True, pitchers_only=True, as_string=False
# )
# for line in home_pitchers:
# try:
# # logging.info(f'line: {line}')
# this_stats = get_pitching_stats(this_game.id, lineup_id=line.id)
# # logging.info(f'home / this_stats: {this_stats}')
# home_stats['p_lines'].extend(this_stats)
# if 'score' not in away_stats:
# # logging.info(f'score not in away_stats')
# away_stats['score'] = this_stats[0]['pl_runs']
# else:
# # logging.info(f'score is in away_stats')
# away_stats['score'] += this_stats[0]['pl_runs']
# if 'hits' not in away_stats:
# # logging.info(f'hits not in away_stats')
# away_stats['hits'] = this_stats[0]['pl_hit']
# else:
# # logging.info(f'hits is in away_stats')
# away_stats['hits'] += this_stats[0]['pl_hit']
# except Exception as e:
# bad_player = await get_player(this_game, line)
# logging.error(f'Unable to process stats for card_id {line.card_id} in Game {this_game.id}: '
# f'{type(e)}: {e}')
# await interaction.edit_original_response(
# content=f'I was not able to process stats for {bad_player["name"]} - '
# f'{get_cal_user(interaction).mention} help!'
# )
#
# logging.debug(f'finished tallying pitcher stats')
#
# # away_stats['score'] = home_stats['p_lines'][0]['tm_runs']
# try:
# decisions = get_pitching_decisions(this_game)
# except AttributeError as e:
# logging.error(f'Could not pull decisions for Game {this_game.id}: {e}')
# await interaction.edit_original_response(
# content=f'I was not able to calculate the Winning and Losing Pitcher for this game. Is the game '
# f'ending early? {get_cal_user(interaction).mention} can probably help.'
# )
# return
# logging.debug(f'decisions: {decisions}')
#
# winning_team = away_team if away_stats['score'] > home_stats['score'] else home_team
# losing_team = away_team if away_stats['score'] < home_stats['score'] else home_team
#
# # Post Game Rewards
# r_data = await self.post_rewards(winning_team, losing_team, this_game)
# win_reward = r_data['win_string']
# loss_reward = r_data['loss_string']
#
# # Check for Gauntlet game so rewards go to main team
# if gauntlet_team is not None:
# if winning_team['gmid'] == gauntlet_team['gmid']:
# winning_team = owner_team
# else:
# losing_team = owner_team
#
# logging.debug(f'away_stats (in /endgame function)\n\n{away_stats}')
# logging.debug(f'home_stats (in /endgame function)\n\n{home_stats}')
# logging.debug(f'winning_team: {winning_team}\nlosing_team: {losing_team}')
#
# logging.debug(f'Time to build statlines and submit the scorecard for this PD game!')
# # Post result
# success = await db_post(
# 'results',
# payload={
# 'away_team_id': this_game.away_team_id,
# 'home_team_id': this_game.home_team_id,
# 'away_score': away_stats['score'],
# 'home_score': home_stats['score'],
# 'away_team_ranking': away_team['ranking'],
# 'home_team_ranking': home_team['ranking'],
# 'scorecard': f'Bot Game {this_game.id}',
# 'week': this_game.week_num,
# 'season': this_game.season,
# 'ranked': this_game.ranked,
# 'short_game': this_game.short_game,
# 'game_type': this_game.game_type
# }
# )
# # Submit the stats
# batter_stats = []
# pitcher_stats = []
# doubles = ''
# triples = ''
# homers = ''
# s_bases = ''
# caught_s = ''
#
# for line in [*away_stats['b_lines'], *home_stats['b_lines']]:
# if line['pl_double']:
# if len(doubles):
# doubles += ', '
# card = await db_get("cards", object_id=line["card_id"])
# doubles += f'{card["player"]["p_name"]}' \
# f'{" " if line["pl_double"] > 1 else ""}' \
# f'{line["pl_double"] if line["pl_double"] > 1 else ""}'
# if line['pl_triple']:
# if len(triples):
# triples += ', '
# card = await db_get("cards", object_id=line["card_id"])
# triples += f'{card["player"]["p_name"]}' \
# f'{" " if line["pl_triple"] > 1 else ""}' \
# f'{line["pl_triple"] if line["pl_triple"] > 1 else ""}'
# if line['pl_homerun']:
# if len(homers):
# homers += ', '
# card = await db_get("cards", object_id=line["card_id"])
# homers += f'{card["player"]["p_name"]}' \
# f'{" " if line["pl_homerun"] > 1 else ""}' \
# f'{line["pl_homerun"] if line["pl_homerun"] > 1 else ""}'
# if line['pl_sb']:
# if len(s_bases):
# s_bases += ', '
# card = await db_get("cards", object_id=line["card_id"])
# s_bases += f'{card["player"]["p_name"]}' \
# f'{" " if line["pl_sb"] > 1 else ""}' \
# f'{line["pl_sb"] if line["pl_sb"] > 1 else ""}'
# batter_stats.append(
# {
# 'card_id': line['card_id'],
# 'team_id': line['team_id'],
# 'roster_num':
# this_game.away_roster_num if this_game.away_team_id == line['team_id']
# else this_game.home_roster_num,
# 'vs_team_id':
# home_team['id'] if this_game.away_team_id == line['team_id']
# else away_team['id'],
# 'pos': line['pos'],
# 'pa': line['pl_pa'],
# 'ab': line['pl_ab'],
# 'run': line['pl_run'],
# 'rbi': line['pl_rbi'],
# 'hit': line['pl_hit'],
# 'double': line['pl_double'],
# 'triple': line['pl_triple'],
# 'hr': line['pl_homerun'],
# 'bb': line['pl_bb'],
# 'so': line['pl_so'],
# 'hbp': line['pl_hbp'],
# 'sac': line['pl_sac'],
# 'ibb': line['pl_ibb'],
# 'gidp': line['pl_gidp'],
# 'sb': line['pl_sb'],
# 'cs': line['pl_cs'],
# 'bphr': line['pl_bphr'],
# 'bpfo': line['pl_bpfo'],
# 'bp1b': line['pl_bp1b'],
# 'bplo': line['pl_bplo'],
# 'week': this_game.week_num,
# 'season': this_game.season,
# 'game_id': this_game.id,
# }
# )
#
# for line in [*away_stats['f_lines'], *home_stats['f_lines']]:
# if line['pl_csc']:
# if len(caught_s):
# caught_s += ', '
# card = await db_get("cards", object_id=line["card_id"])
# caught_s += f'{card["player"]["p_name"]}' \
# f'{" " if line["pl_csc"] > 1 else ""}' \
# f'{line["pl_csc"] if line["pl_csc"] > 1 else ""}'
# batter_stats.append(
# {
# 'card_id': line['card_id'],
# 'team_id': line['team_id'],
# 'roster_num':
# this_game.away_roster_num if this_game.away_team_id == line['team_id']
# else this_game.home_roster_num,
# 'vs_team_id':
# home_team['id'] if this_game.away_team_id == line['team_id']
# else away_team['id'],
# 'pos': line['pos'],
# 'xch': line['pl_xch'],
# 'xhit': line['pl_xhit'],
# 'error': line['pl_error'],
# 'pb': line['pl_pb'],
# 'sbc': line['pl_sbc'],
# 'csc': line['pl_csc'],
# 'week': this_game.week_num,
# 'season': this_game.season,
# 'game_id': this_game.id
# }
# )
#
# for line in [*away_stats['p_lines'], *home_stats['p_lines']]:
# pitcher_stats.append(
# {
# 'card_id': line['card_id'],
# 'team_id': line['team_id'],
# 'roster_num':
# this_game.away_roster_num if this_game.away_team_id == line['team_id']
# else this_game.home_roster_num,
# 'vs_team_id':
# home_team['id'] if this_game.away_team_id == line['team_id']
# else away_team['id'],
# 'ip': (math.floor(line['pl_outs'] / 3) * 1.0) + ((line['pl_outs'] % 3) / 3.0),
# 'hit': line['pl_hit'],
# 'run': line['pl_runs'],
# 'erun': line['pl_eruns'],
# 'so': line['pl_so'],
# 'bb': line['pl_bb'],
# 'hbp': line['pl_hbp'],
# 'wp': line['pl_wild_pitch'],
# 'balk': line['pl_balk'],
# 'hr': line['pl_homerun'],
# 'ir': 0,
# 'irs': 0,
# 'gs': 1 if line['card_id'] in decisions['starters'] else 0,
# 'win': 1 if line['card_id'] == decisions['winner'] else 0,
# 'loss': 1 if line['card_id'] == decisions['loser'] else 0,
# 'hold': 1 if line['card_id'] in decisions['holds'] else 0,
# 'sv': 1 if line['card_id'] == decisions['save'] else 0,
# 'bsv': 1 if line['card_id'] in decisions['b_save'] else 0,
# 'week': this_game.week_num,
# 'season': this_game.season,
# 'game_id': this_game.id
# }
# )
#
# doubles += '\n' if len(doubles) else ''
# triples += '\n' if len(triples) else ''
# homers += '\n' if len(homers) else ''
# s_bases += '\n' if len(s_bases) else ''
# caught_s += '\n' if len(caught_s) else ''
#
# await db_post('batstats', payload={'stats': batter_stats})
# await db_post('pitstats', payload={'stats': pitcher_stats})
#
# # Post a notification to PD
# last_play = get_current_play(this_game.id)
# inning = f'{last_play.inning_num if last_play.inning_half == "Bot" else last_play.inning_num - 1}'
# embed = get_team_embed(
# f'{away_team["lname"]} {away_stats["score"]} @ {home_stats["score"]} {home_team["lname"]} - F/'
# f'{inning}',
# winning_team
# )
#
# if this_game.game_type == 'major-league':
# game_des = 'Major League'
# elif this_game.game_type == 'minor-league':
# game_des = 'Minor League'
# elif this_game.game_type == 'hall-of-fame':
# game_des = 'Hall of Fame'
# elif this_game.ranked:
# game_des = 'Ranked'
# elif 'gauntlet' in this_game.game_type:
# game_des = 'Gauntlet'
# else:
# game_des = 'Unlimited'
# embed.description = f'Score Report - {game_des} ' \
# f'{"- 3-Inning Game" if this_game.short_game else " - 9-Inning Game"}'
# embed.add_field(
# name='Box Score',
# value=get_final_scorebug(away_team, home_team, away_stats, home_stats),
# inline=False
# )
# embed.add_field(
# name='Location',
# value=f'{interaction.guild.get_channel(this_game.channel_id).mention}'
# )
# wc_query = await db_get("cards", object_id=decisions["winner"])
# lc_query = await db_get("cards", object_id=decisions["loser"])
# if decisions["save"]:
# sv_query = await db_get("cards", object_id=decisions["save"])
# embed.add_field(
# name='Pitching',
# value=f'Win: {wc_query["player"]["p_name"]}\n'
# f'Loss: {lc_query["player"]["p_name"]}\n'
# f'{"Save: " if decisions["save"] else ""}'
# f'{sv_query["player"]["p_name"] if decisions["save"] else ""}',
# inline=False
# )
# if len(doubles) + len(triples) + len(homers) > 0:
# embed.add_field(
# name='Batting',
# value=f'{"2B: " if len(doubles) else ""}{doubles if len(doubles) else ""}'
# f'{"3B: " if len(triples) else ""}{triples if len(triples) else ""}'
# f'{"HR: " if len(homers) else ""}{homers if len(homers) else ""}',
# inline=False
# )
# if len(s_bases) + len(caught_s) > 0:
# embed.add_field(
# name='Baserunning',
# value=f'{"SB: " if len(s_bases) else ""}{s_bases if len(s_bases) else ""}'
# f'{"CSc: " if len(caught_s) else ""}{caught_s if len(caught_s) else ""}',
# inline=False
# )
# embed.add_field(
# name=f'{winning_team["abbrev"]} Rewards',
# value=win_reward
# )
# embed.add_field(
# name=f'{losing_team["abbrev"]} Rewards',
# value=loss_reward
# )
# embed.add_field(
# name='Highlights',
# value=f'Please share the highlights in {get_channel(interaction, "pd-news-ticker").mention}!',
# inline=False
# )
# await send_to_channel(self.bot, 'pd-network-news', embed=embed)
#
# # Gauntlet results and reward
# if gauntlet_team is not None:
# await gauntlets.post_result(
# int(this_game.game_type.split('-')[3]),
# is_win=winning_team['gmid'] == gauntlet_team['gmid'],
# this_team=gauntlet_team,
# bot=self.bot,
# channel=interaction.channel
# )
#
# this_run = await db_get('gauntletruns', object_id=int(this_game.game_type.split('-')[3]))
# if this_run['losses'] == 2:
# await send_to_channel(
# bot=self.bot,
# channel_name='pd-network-news',
# content=f'The {gauntlet_team["lname"]} won {this_run["wins"]} games before failing in the '
# f'{this_run["gauntlet"]["name"]} gauntlet.',
# embed=None
# )
#
# patch_game(this_game.id, active=False)
#
# logging.info(f'Game {this_game.id} is complete')
# if gauntlet_team is None:
# await interaction.edit_original_response(
# content=f'Good game! Go share the highlights in '
# f'{get_channel(interaction, "pd-news-ticker").mention}!'
# )
@app_commands.command( @app_commands.command(
name='read-lineup', name='read-lineup',

View File

@ -2,13 +2,16 @@ import copy
import datetime import datetime
import logging import logging
import random import random
from typing import Literal
import discord import discord
from discord import SelectOption
from in_game import ai_manager from in_game import ai_manager
import helpers import helpers
from helpers import RARITY, get_or_create_role, send_to_channel, get_channel from helpers import RARITY, get_or_create_role, send_to_channel, get_channel
from db_calls import db_get, db_post, db_delete, db_patch from db_calls import db_get, db_post, db_delete, db_patch
from utilities.dropdown import DropdownView, SelectPokemonEvolution
async def wipe_team(this_team, interaction: discord.Interaction, delete_team: bool = False, delete_runs: bool = False): async def wipe_team(this_team, interaction: discord.Interaction, delete_team: bool = False, delete_runs: bool = False):
@ -212,6 +215,31 @@ async def get_opponent(this_team, this_event, this_run):
else: else:
raise KeyError(f'Hmm...I do not know who you should be playing right now.') raise KeyError(f'Hmm...I do not know who you should be playing right now.')
return await db_get('teams', object_id=t_id, none_okay=False) return await db_get('teams', object_id=t_id, none_okay=False)
elif this_event['id'] == 7:
if gp == 0:
t_id = 10
elif gp == 1:
t_id = 20
elif gp == 2:
t_id = 25
elif gp == 3:
t_id = 27
elif gp == 4:
t_id = 6
elif gp == 5:
t_id = 5
elif gp == 6:
t_id = 4
elif gp == 7:
t_id = 16
elif gp == 8:
t_id = 13
elif gp == 9:
t_id = 30
elif gp == 10:
t_id = 17
else:
raise KeyError(f'Hmm...I do not know who you should be playing right now.')
else: else:
return None return None
@ -237,70 +265,6 @@ async def get_starting_pitcher(this_team, this_game, this_event, this_run):
'after_play': 0 'after_play': 0
} }
# if this_event['id'] == 1:
# if this_team['id'] != 58:
# set_params = copy.deepcopy(ai_manager.MINOR_CARDSET_PARAMS)
# else:
# set_params = []
# params = [
# ('mlbclub', this_team['lname']), ('pos_include', 'SP'), ('pos_exclude', 'RP'),
# ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5)
# ]
# params.extend(set_params)
# elif this_event['id'] == 2:
# set_params = copy.deepcopy(ai_manager.GAUNTLET2_PARAMS)
# params = [
# ('mlbclub', this_team['lname']), ('pos_include', 'SP'), ('pos_exclude', 'RP'),
# ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5)
# ]
# params.extend(set_params)
# else:
# raise KeyError(f'Pitcher not found for Gauntlet {this_event["id"]}')
#
# params = [
# ('mlbclub', this_team['lname']), ('pos_include', 'SP'), ('pos_exclude', 'RP'),
# ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5)
# ]
# counter = 0
# while True:
# counter += 1
# # Pull starters sorted by current cost
# try:
# params.extend(set_params)
# pitchers = await db_get(
# endpoint='players',
# params=params,
# timeout=10
# )
# except ConnectionError as e:
# logging.error(f'Could not get pitchers for {this_team["lname"]}: {e}')
# raise ConnectionError(f'Error pulling starting pitchers for the {this_team["lname"]}. Cal help plz.')
#
# if pitchers['count'] == 0:
# logging.info(f'pitchers is None')
# del params
# params = [
# ('mlbclub', this_team['lname']), ('pos_include', 'SP'),
# ('inc_dex', False), ('sort_by', 'cost-desc'), ('limit', 5)
# ]
# elif counter > 2:
# raise KeyError(f'Error pulling pitchers for the {this_team["lname"]}. Cal help plz.')
# else:
# break
#
# pitcher_num = games_played(this_run) % 5
# card_id = await ai_manager.get_or_create_card(pitchers['players'][pitcher_num], this_team)
#
# return {
# 'game_id': this_game.id,
# 'team_id': this_team['id'],
# 'player_id': pitchers['players'][0]['player_id'],
# 'card_id': card_id,
# 'position': 'P',
# 'batting_order': 10,
# 'after_play': 0
# }
async def run_draft(interaction: discord.Interaction, main_team, this_event, draft_team=None): async def run_draft(interaction: discord.Interaction, main_team, this_event, draft_team=None):
if this_event['id'] == 1: if this_event['id'] == 1:
@ -332,6 +296,10 @@ async def run_draft(interaction: discord.Interaction, main_team, this_event, dra
embed_description = f'{this_event["name"]}' embed_description = f'{this_event["name"]}'
base_params = [('cardset_id', 20), ('cardset_id', 21), ('cardset_id', 22), ('cardset_id', 16), base_params = [('cardset_id', 20), ('cardset_id', 21), ('cardset_id', 22), ('cardset_id', 16),
('cardset_id', 8), ('limit', 8)] ('cardset_id', 8), ('limit', 8)]
elif this_event['id'] == 7:
embed_title = f'{main_team['lname']} - {this_event['name']} Draft'
embed_description = f'{this_event["name"]}'
base_params = [('cardset_id', 5), ('cardset_id', 1), ('cardset_id', 3), ('cardset_id', 4), ('cardset_id', 23), ('cardset_id', 22), ('limit', 4)]
else: else:
logging.error(f'run_draft - Event ID {this_event["id"]} not recognized') logging.error(f'run_draft - Event ID {this_event["id"]} not recognized')
raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}') raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}')
@ -586,19 +554,30 @@ async def run_draft(interaction: discord.Interaction, main_team, this_event, dra
for z in helpers.get_all_pos(y): for z in helpers.get_all_pos(y):
all_str[z] += f'{name_string}\n' all_str[z] += f'{name_string}\n'
top_embed.add_field(name=f'HoFs ({counts["Hall of Fame"]}/{max_counts["Hall of Fame"]})', value=all_str['Hall of Fame'], inline=False) if max_counts['Hall of Fame'] > 0:
top_embed.add_field(name=f'MVPs ({counts["MVP"]}/{max_counts["MVP"]})', value=all_str['MVP'], inline=False) top_embed.add_field(name=f'HoFs ({counts["Hall of Fame"]}/{max_counts["Hall of Fame"]})', value=all_str['Hall of Fame'], inline=False)
top_embed.add_field(
name=f'All-Stars ({counts["All-Star"]}/{max_counts["All-Star"]})', value=all_str['All-Star'], inline=False) if max_counts['MVP'] > 0:
top_embed.add_field( top_embed.add_field(name=f'MVPs ({counts["MVP"]}/{max_counts["MVP"]})', value=all_str['MVP'], inline=False)
name=f'Starters ({counts["Starter"]}/{max_counts["Starter"]})', value=all_str['Starter'], inline=False)
top_embed.add_field( if max_counts['All-Star'] > 0:
name=f'Reserves ({counts["Reserve"]}/{max_counts["Reserve"]})', value=all_str['Reserve'], inline=False) top_embed.add_field(
top_embed.add_field( name=f'All-Stars ({counts["All-Star"]}/{max_counts["All-Star"]})', value=all_str['All-Star'], inline=False)
name=f'Replacements ({counts["Replacement"]}/{max_counts["Replacement"]})',
value=all_str['Replacement'], if max_counts['Starter'] > 0:
inline=False top_embed.add_field(
) name=f'Starters ({counts["Starter"]}/{max_counts["Starter"]})', value=all_str['Starter'], inline=False)
if max_counts['Reserve'] > 0:
top_embed.add_field(
name=f'Reserves ({counts["Reserve"]}/{max_counts["Reserve"]})', value=all_str['Reserve'], inline=False)
if max_counts['Replacement'] > 0:
top_embed.add_field(
name=f'Replacements ({counts["Replacement"]}/{max_counts["Replacement"]})',
value=all_str['Replacement'],
inline=False
)
bot_embed.add_field(name=f'Catcher', value=all_str['C'], inline=False) bot_embed.add_field(name=f'Catcher', value=all_str['C'], inline=False)
bot_embed.add_field(name=f'First Base', value=all_str['1B'], inline=False) bot_embed.add_field(name=f'First Base', value=all_str['1B'], inline=False)
@ -1507,6 +1486,164 @@ async def run_draft(interaction: discord.Interaction, main_team, this_event, dra
await last_message.edit(content=None, embeds=get_embeds(include_links=False)) await last_message.edit(content=None, embeds=get_embeds(include_links=False))
elif this_event['id'] in [5, 6]: elif this_event['id'] in [5, 6]:
await draft_loop() await draft_loop()
elif this_event['id'] == 7:
round_num = 1
counter = 0
while round_num <= 26 and counter < 50:
counter += 1
params = copy.deepcopy(base_params)
logging.info(f'gauntlets.py - run_draft - event_id {this_event["id"]} / round_num: {round_num} / counter: {counter} / counts: {counts} / max_counts: {max_counts}')
# Set rarity based on remaining counts
if counts['Hall of Fame'] < max_counts['Hall of Fame']:
params.extend([
('min_rarity', RARITY['HoF']), ('max_rarity', RARITY['HoF'])
])
elif counts['MVP'] < max_counts['MVP']:
params.extend([
('min_rarity', RARITY['MVP']), ('max_rarity', RARITY['MVP'])
])
elif counts['All-Star'] < max_counts['All-Star']:
params.extend([
('min_rarity', RARITY['All-Star']), ('max_rarity', RARITY['All-Star'])
])
elif counts['Starter'] < max_counts['Starter']:
if counts['Starter'] < 5:
params = [('cardset_id', 23), ('limit', 16)]
params.extend([
('min_rarity', RARITY['Starter']), ('max_rarity', RARITY['Starter'])
])
elif counts['Reserve'] < max_counts['Reserve']:
params.extend([
('min_rarity', RARITY['Reserve']), ('max_rarity', RARITY['Reserve'])
])
else:
params.extend([
('min_rarity', RARITY['Replacement']), ('max_rarity', RARITY['Replacement'])
])
this_batch = []
for x in ['SP', 'RP', 'IF', 'OF']:
# Slot 1 - SP
if x == 'SP':
if counts['SP'] > 5:
slot_params = [('pos_exc', 'SP')]
if counts['RP'] > 7:
slot_params = [('pos_exc', 'RP')]
else:
slot_params = [('pos_inc', 'SP')]
# if counts['SP'] > 5:
# slot_params = [('pos_exc', 'SP')]
# elif counts['RP'] < 6:
# slot_params = [('pos_inc', 'RP')]
# else:
# slot_params = [('pos_exc', 'SP'), ('pos_exc', 'RP')]
# Slot 2 - RP
elif x == 'RP':
logging.info(f'counts[RP]: {counts["RP"]}')
if counts['RP'] > 7:
slot_params = [('pos_exc', 'RP')]
if counts['SP'] > 5:
slot_params = [('pos_exc', 'SP')]
else:
slot_params = [('pos_inc', 'RP')]
# Slot 3 - IF
elif x == 'IF':
slot_params = []
for y in ['1B', '2B', '3B', 'SS', 'C']:
if (counts[y] > 1) and 0 in [
counts['C'], counts['1B'], counts['2B'], counts['3B'], counts['SS']
]:
slot_params.append(('pos_exc', y))
elif (y == 'C' and counts['C'] < 3) or (y != 'C' and counts[y] < 4):
slot_params.append(('pos_inc', y))
# if counts['C'] < 2:
# slot_params.append(('pos_inc', 'C'))
# if len(slot_params) == 0:
# slot_params = [('pos_exc', 'C'), ('pos_exc', '1B'), ('pos_exc', '2B'), ('pos_exc', '3B'),
# ('pos_exc', 'SS')]
# Slot 4 - OF
else:
slot_params = []
for y in ['LF', 'CF', 'RF']:
if counts[y] > 4:
slot_params.append(('pos_exc', y))
elif counts[y] > 1 and 0 in [counts['LF'], counts['CF'], counts['RF']]:
slot_params.append(('pos_exc', y))
elif counts[y] < 5:
slot_params.append(('pos_inc', y))
# if len(slot_params) == 0:
# slot_params = [('pos_exc', 'LF'), ('pos_exc', 'CF'), ('pos_exc', 'RF')]
logging.info(f'this_batch: {this_batch}')
logging.info(f'slot_params: {slot_params}')
logging.info(f'params: {params}')
# No position explicitly requested or denied
if len(slot_params) == 0:
if (counts['SP'] + counts['RP']) > (
counts['C'] + counts['1B'] + counts['2B'] + counts['SS'] + counts['LF'] + counts['CF'] +
counts['RF']):
pos_counts = [
('C', counts['C']), ('1B', counts['1B']), ('2B', counts['2B']), ('3B', counts['3B']),
('SS', counts['SS']), ('LF', counts['LF']), ('CF', counts['CF']), ('RF', counts['RF'])
]
pos_counts.sort(key=lambda z: z[1])
slot_params = [('pos_inc', pos_counts[0][0])]
else:
if counts['SP'] >= counts['RP']:
slot_params = [('pos_inc', 'RP')]
else:
slot_params = [('pos_inc', 'SP')]
slot_params.extend(params)
p_query = await db_get('players/random', params=slot_params)
if p_query['count'] > 0:
for i in p_query['players']:
if i['p_name'] not in p_names and i not in this_batch:
if i['cardset']['id'] == 23 and '420420' not in i['strat_code']:
pass
else:
this_batch.append(i)
break
if len(this_batch) < 4:
logging.error(f'Pulled less than 4 players in gauntlet draft')
p_query = await db_get('players/random', params=params)
for i in p_query['players']:
if i['p_name'] not in p_names and i not in this_batch:
this_batch.append(i)
if len(this_batch) >= 4:
break
if len(this_batch) < 4:
raise KeyError(f'This is embarassing, but I couldn\'t find enough players for you to draft from.')
# Present choices and capture selection
p_choice = await helpers.get_choice_from_cards(interaction, this_batch, delete_message=True)
# Add player to list and update counts
p_names.append(p_choice['p_name'])
counts[p_choice['rarity']['name']] += 1
all_players.append(p_choice)
if p_choice['pos_1'] in ['SP', 'RP']:
counts[p_choice['pos_1']] += 1
else:
for x in helpers.get_all_pos(p_choice):
if x in counts:
counts[x] += 1
# Update roster embed
round_num += 1
await last_message.edit(content=None, embeds=get_embeds(include_links=False, round_num=round_num))
else: else:
logging.error(f'run_draft - No draft logic for Event ID {this_event["id"]}') logging.error(f'run_draft - No draft logic for Event ID {this_event["id"]}')
raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}') raise KeyError(f'Draft data not found for Gauntlet {this_event["id"]}')
@ -1634,6 +1771,28 @@ async def end_run(this_run, this_event, this_team):
return l_message return l_message
async def evolve_pokemon(this_team, channel):
c_query = await db_get(
'cards',
params=[('team_id', this_team['id']), ('order_by', 'new'), ('limit', 26)]
)
evolvable_mons = [x for x in c_query['cards'] if x['player']['cardset']['id'] in [23] and x['player']['fangr_id'] is not None and len(x['player']['fangr_id']) > 3]
if len(evolvable_mons) > 0:
evo_target_options = [
SelectOption(label=f'{x["player"]["rarity"]["name"]} | {x["player"]["p_name"]}', value=x['id']) for x in evolvable_mons
]
view = DropdownView(
dropdown_objects=[SelectPokemonEvolution(options=evo_target_options, this_team=this_team)]
)
await channel.send(
content='What? One of your pokemon is ready to evolve!\n\n-# The selected pokemon will be removed from your team and replaced with its evolution',
view=view
)
else:
await channel.send('All of your Pokemon are fully evolved!')
async def post_result(run_id: int, is_win: bool, this_team, bot, channel): async def post_result(run_id: int, is_win: bool, this_team, bot, channel):
this_run = await db_get('gauntletruns', object_id=run_id) this_run = await db_get('gauntletruns', object_id=run_id)
this_event = await db_get('events', object_id=this_run['gauntlet']['id']) this_event = await db_get('events', object_id=this_run['gauntlet']['id'])
@ -1678,7 +1837,7 @@ async def post_result(run_id: int, is_win: bool, this_team, bot, channel):
team_id = None team_id = None
if x['reward']['pack_type']['id'] == 9: if x['reward']['pack_type']['id'] == 9:
cardset_id = 18 cardset_id = 18
else: elif this_event['id'] == 6:
cardset_id = 20 cardset_id = 20
team_id = None team_id = None
if x['reward']['pack_type']['id'] == 9: if x['reward']['pack_type']['id'] == 9:
@ -1692,6 +1851,19 @@ async def post_result(run_id: int, is_win: bool, this_team, bot, channel):
}]} }]}
) )
reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack' reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack'
elif x['reward']['pack_type'] and this_event['id'] in [7]:
if this_event['id'] == 7:
cardset_id = 23
team_id = 91
await db_post(
'packs', payload={'packs': [{
'team_id': main_team['id'],
'pack_type_id': x['reward']['pack_type']['id'],
'pack_cardset_id': cardset_id if x['reward']['pack_type']['id'] != 8 else None,
'pack_team_id': team_id if x['reward']['pack_type']['id'] == 8 else None
}]}
)
reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack'
elif x['reward']['pack_type']: elif x['reward']['pack_type']:
await helpers.give_packs(main_team, 1, x['reward']['pack_type']) await helpers.give_packs(main_team, 1, x['reward']['pack_type'])
reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack' reward_string += f'- 1x {x["reward"]["pack_type"]["name"]} Pack'
@ -1744,4 +1916,9 @@ async def post_result(run_id: int, is_win: bool, this_team, bot, channel):
embed=await get_embed(this_run) embed=await get_embed(this_run)
) )
# Evolve a card!
if this_run['id'] == 7 and this_run['wins'] < 10 and this_run['losses'] < 2:
await evolve_pokemon(this_team, channel)

View File

@ -27,6 +27,7 @@ PD_PLAYERS = 'Paper Dynasty Players'
SBA_PLAYERS_ROLE_NAME = f'Season {SBA_SEASON} Players' SBA_PLAYERS_ROLE_NAME = f'Season {SBA_SEASON} Players'
PD_PLAYERS_ROLE_NAME = f'Paper Dynasty Players' PD_PLAYERS_ROLE_NAME = f'Paper Dynasty Players'
PD_CARD_URL = 'https://sombaseball.ddns.net/cards/pd' 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_BATTER_FORMULA = '=IMPORTRANGE("1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE","guide_Batters!A1:CD")'
RATINGS_PITCHER_FORMULA = '=IMPORTRANGE("1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE","guide_Pitchers!A1:BQ")' RATINGS_PITCHER_FORMULA = '=IMPORTRANGE("1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE","guide_Pitchers!A1:BQ")'
RATINGS_SHEET_KEY = '1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE' RATINGS_SHEET_KEY = '1zDmlOw94gTzOAjqOpNdDZsg0O6rxNWkL4-XT6-iL2IE'
@ -68,6 +69,7 @@ IMAGES = {
'pack-sta': f'{PD_CARD_URL}/pack-standard.png', 'pack-sta': f'{PD_CARD_URL}/pack-standard.png',
'pack-pre': f'{PD_CARD_URL}/pack-premium.png', 'pack-pre': f'{PD_CARD_URL}/pack-premium.png',
'pack-mar': f'{PD_CARD_URL}/sluggers/mario-gauntlet.png', 'pack-mar': f'{PD_CARD_URL}/sluggers/mario-gauntlet.png',
'pack-pkmnbs': f'https://i.postimg.cc/635M4X52/pokemon-brilliantstars.jpg',
'mvp': { 'mvp': {
'Arizona Diamondbacks': f'{PD_CARD_URL}/mvp/arizona-diamondbacks.gif', 'Arizona Diamondbacks': f'{PD_CARD_URL}/mvp/arizona-diamondbacks.gif',
'Atlanta Braves': f'{PD_CARD_URL}/mvp/atlanta-braves.gif', 'Atlanta Braves': f'{PD_CARD_URL}/mvp/atlanta-braves.gif',
@ -102,7 +104,8 @@ IMAGES = {
'Toronto Blue Jays': f'{PD_CARD_URL}/mvp/toronto-blue-jays.gif', 'Toronto Blue Jays': f'{PD_CARD_URL}/mvp/toronto-blue-jays.gif',
'Washington Nationals': f'{PD_CARD_URL}/mvp/washington-nationals.gif', 'Washington Nationals': f'{PD_CARD_URL}/mvp/washington-nationals.gif',
'Junior All Stars': f'{PD_CARD_URL}/mvp.png', 'Junior All Stars': f'{PD_CARD_URL}/mvp.png',
'Mario Super Sluggers': f'{PD_CARD_URL}/mvp.png' 'Mario Super Sluggers': f'{PD_CARD_URL}/mvp.png',
'Pokemon': 'https://i.postimg.cc/ydzYB7BR/masterball.jpg'
}, },
'gauntlets': f'{PD_CARD_URL}/gauntlets.png' 'gauntlets': f'{PD_CARD_URL}/gauntlets.png'
} }
@ -241,7 +244,7 @@ SELECT_CARDSET_OPTIONS = [
discord.SelectOption(label='2013 Season', value='6'), discord.SelectOption(label='2013 Season', value='6'),
discord.SelectOption(label='2012 Season', value='7') discord.SelectOption(label='2012 Season', value='7')
] ]
ACTIVE_EVENT_LITERAL = Literal['1998 Season'] ACTIVE_EVENT_LITERAL = Literal['1998 Season', 'Brilliant Stars']
class Question: class Question:
@ -849,6 +852,7 @@ class SelectBuyPacksCardset(discord.ui.Select):
def __init__(self, team: dict, quantity: int, pack_type_id: int, pack_embed: discord.Embed, cost: int): def __init__(self, team: dict, quantity: int, pack_type_id: int, pack_embed: discord.Embed, cost: int):
options = [ options = [
discord.SelectOption(label='1998 Live'), discord.SelectOption(label='1998 Live'),
discord.SelectOption(label='Pokemon - Brilliant Stars'),
discord.SelectOption(label='2024 Season'), discord.SelectOption(label='2024 Season'),
discord.SelectOption(label='2023 Season'), discord.SelectOption(label='2023 Season'),
discord.SelectOption(label='2022 Season'), discord.SelectOption(label='2022 Season'),
@ -892,6 +896,9 @@ class SelectBuyPacksCardset(discord.ui.Select):
cardset_id = 17 cardset_id = 17
elif self.values[0] == '1998 Live': elif self.values[0] == '1998 Live':
cardset_id = 20 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]}' self.pack_embed.description = f'{self.pack_embed.description} - {self.values[0]}'
view = Confirm(responders=[interaction.user], timeout=30) view = Confirm(responders=[interaction.user], timeout=30)
@ -1735,7 +1742,10 @@ async def get_card_embeds(card, include_stats=False) -> list:
# embed.add_field(name='# Dupes', value=f'{count - 1} dupe{"s" if count - 1 != 1 else ""}') # 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"]}') # embed.add_field(name='Team', value=f'{card["player"]["mlbclub"]}')
player_pages = f'[BBRef]({get_player_url(card["player"], "bbref")})' 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.add_field(name='Player Page', value=f'{player_pages}')
embed.set_image(url=card["player"]["image"]) embed.set_image(url=card["player"]["image"])
@ -1744,6 +1754,28 @@ async def get_card_embeds(card, include_stats=False) -> list:
embed.set_thumbnail(url=headshot) embed.set_thumbnail(url=headshot)
else: else:
embed.set_thumbnail(url=IMAGES['logo']) 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 include_stats:
if b_query['count'] > 0: if b_query['count'] > 0:
@ -2244,6 +2276,7 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list:
if pl['count'] != counts[key]['count']: if pl['count'] != counts[key]['count']:
mvp_flag = counts[key]['count'] - pl['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']: for x in pl['players']:
this_pack_players.append(x) this_pack_players.append(x)
@ -2252,12 +2285,21 @@ async def roll_for_cards(all_packs: list, extra_val=None) -> list:
if x['rarity']['value'] >= 3: if x['rarity']['value'] >= 3:
pull_notifs.append(x) pull_notifs.append(x)
if mvp_flag: 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)]) pl = await db_get('players/random', params=[('min_rarity', 5), ('limit', mvp_flag)])
for x in pl['players']: for x in pl['players']:
this_pack_players.append(x) this_pack_players.append(x)
all_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( success = await db_post(
'cards', 'cards',
@ -2878,7 +2920,9 @@ async def paperdex_team_embed(team: dict, mlb_team: dict) -> list[discord.Embed]
def get_pack_cover(pack): def get_pack_cover(pack):
if pack['pack_type']['name'] in ['Premium', 'MVP']: 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'] return IMAGES['pack-pre']
elif pack['pack_type']['name'] == 'Standard': elif pack['pack_type']['name'] == 'Standard':
return IMAGES['pack-sta'] return IMAGES['pack-sta']

364
utilities/buttons.py Normal file
View File

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

335
utilities/dropdown.py Normal file
View File

@ -0,0 +1,335 @@
import asyncio
import datetime
from typing import List
import discord
import logging
from discord import SelectOption
from discord.utils import MISSING
# from sqlmodel import Session
from db_calls import db_delete, db_get, db_post
# from exceptions import CardNotFoundException, PlayNotFoundException, log_exception
from helpers import get_card_embeds
# from in_game.game_helpers import legal_check
# from in_game.gameplay_models import Game, Lineup, Play, Team
# from in_game.gameplay_queries import get_one_lineup, get_position, get_card_or_none
from utilities.buttons import ask_confirm
logger = logging.getLogger('discord_app')
class DropdownOptions(discord.ui.Select):
def __init__(self, option_list: list, placeholder: str = 'Make your selection', min_values: int = 1, max_values: int = 1, callback=None):
# Set the options that will be presented inside the dropdown
# options = [
# discord.SelectOption(label='Red', description='Your favourite colour is red', emoji='🟥'),
# discord.SelectOption(label='Green', description='Your favourite colour is green', emoji='🟩'),
# discord.SelectOption(label='Blue', description='Your favourite colour is blue', emoji='🟦'),
# ]
# The placeholder is what will be shown when no option is chosen
# The min and max values indicate we can only pick one of the three options
# The options parameter defines the dropdown options. We defined this above
# If a default option is set on any SelectOption, the View will not process if only the default is
# selected by the user
self.custom_callback = callback
super().__init__(
placeholder=placeholder,
min_values=min_values,
max_values=max_values,
options=option_list
)
async def callback(self, interaction: discord.Interaction):
# Use the interaction object to send a response message containing
# the user's favourite colour or choice. The self object refers to the
# Select object, and the values attribute gets a list of the user's
# selected options. We only want the first one.
# await interaction.response.send_message(f'Your favourite colour is {self.values[0]}')
logger.info(f'Dropdown callback: {self.custom_callback}')
await self.custom_callback(interaction, self.values)
class DropdownView(discord.ui.View):
"""
https://discordpy.readthedocs.io/en/latest/interactions/api.html#select
"""
def __init__(self, dropdown_objects: list[discord.ui.Select], timeout: float = 300.0):
super().__init__(timeout=timeout)
# self.add_item(Dropdown())
for x in dropdown_objects:
self.add_item(x)
# class SelectViewDefense(discord.ui.Select):
# def __init__(self, options: list, this_play: Play, base_embed: discord.Embed, session: Session, sorted_lineups: list[Lineup]):
# self.embed = base_embed
# self.session = session
# self.play = this_play
# self.sorted_lineups = sorted_lineups
# super().__init__(options=options)
# async def callback(self, interaction: discord.Interaction):
# logger.info(f'SelectViewDefense - selection: {self.values[0]}')
# this_lineup = self.session.get(Lineup, self.values[0])
# self.embed.set_image(url=this_lineup.player.image)
# select_player_options = [
# discord.SelectOption(label=f'{x.position} - {x.player.name}', value=f'{x.id}', default=this_lineup.position == x.position) for x in self.sorted_lineups
# ]
# player_dropdown = SelectViewDefense(
# options=select_player_options,
# this_play=self.play,
# base_embed=self.embed,
# session=self.session,
# sorted_lineups=self.sorted_lineups
# )
# new_view = DropdownView(
# dropdown_objects=[player_dropdown],
# timeout=60
# )
# await interaction.response.edit_message(content=None, embed=self.embed, view=new_view)
# class SelectStartingPitcher(discord.ui.Select):
# def __init__(self, this_game: Game, this_team: Team, session: Session, league_name: str, custom_id: str = MISSING, placeholder: str | None = None, options: List[SelectOption] = ...) -> None:
# logger.info(f'Inside SelectStartingPitcher init function')
# self.game = this_game
# self.team = this_team
# self.session = session
# self.league_name = league_name
# super().__init__(custom_id=custom_id, placeholder=placeholder, options=options)
# async def callback(self, interaction: discord.Interaction):
# logger.info(f'SelectStartingPitcher - selection: {self.values[0]}')
# # Get Human SP card
# human_sp_card = await get_card_or_none(self.session, card_id=self.values[0])
# if human_sp_card is None:
# log_exception(CardNotFoundException, f'Card ID {self.values[0]} not found')
# if human_sp_card.team_id != self.team.id:
# logger.error(f'Card_id {self.values[0]} does not belong to {self.team.abbrev} in Game {self.game.id}')
# await interaction.channel.send(
# f'Uh oh. Card ID {self.values[0]} is {human_sp_card.player.name} and belongs to {human_sp_card.team.sname}. Will you double check that before we get started?'
# )
# return
# await get_position(self.session, human_sp_card, 'P')
# legal_data = await legal_check([self.values[0]], difficulty_name=self.league_name)
# if not legal_data['legal']:
# await interaction.edit_original_response(
# content=f'It looks like this is a Ranked Legal game and {human_sp_card.player.name_with_desc} is not legal in {self.league_name} games. You can start a new game once you pick a new SP.'
# )
# return
# human_sp_lineup = Lineup(
# team_id=self.team.id,
# player_id=human_sp_card.player.id,
# card_id=self.values[0],
# position='P',
# batting_order=10,
# is_fatigued=False,
# game=self.game
# )
# self.session.add(human_sp_lineup)
# self.session.commit()
# await interaction.response.edit_message(
# content=f'The {self.team.lname} are starting {human_sp_card.player.name_with_desc}',
# view=None
# )
# class SelectSubPosition(discord.ui.Select):
# def __init__(self, session: Session, this_lineup: Lineup, custom_id = ..., placeholder = None, options: List[SelectOption] = ...):
# self.session = session
# self.this_lineup = this_lineup
# super().__init__(custom_id=custom_id, placeholder=placeholder, min_values=1, max_values=1, options=options, disabled=False)
# async def callback(self, interaction: discord.Interaction):
# logger.info(f'Setting sub position to {self.values[0]}')
# await interaction.edit_original_response(view=None)
# if self.values[0] == 'PH':
# await interaction.channel.send(content=f'Their position is set to Pinch Hitter.')
# return
# else:
# await get_position(self.session, self.this_lineup.card_id, position=self.values[0])
# self.this_lineup.position = self.values[0]
# for option in self.options:
# if option.value == self.values[0]:
# this_label = option.label
# self.this_lineup.position = self.values[0]
# self.session.add(self.this_lineup)
# self.session.commit()
# await interaction.channel.send(content=f'Their position is set to {this_label}.')
# class SelectBatterSub(discord.ui.Select):
# def __init__(self, this_game: Game, this_team: Team, session: Session, batting_order: int, custom_id: str = MISSING, placeholder: str | None = None, options: List[SelectOption] = ...):
# logger.info(f'Inside SelectBatterSub init function')
# self.game = this_game
# self.team = this_team
# self.session = session
# # self.league_name = league_name
# self.batting_order = batting_order
# super().__init__(custom_id=custom_id, placeholder=placeholder, min_values=1, max_values=1, options=options)
# async def callback(self, interaction: discord.Interaction):
# await interaction.response.defer()
# logger.info(f'Setting batter sub to Card ID: {self.values[0]}')
# # Get Human batter card
# human_batter_card = await get_card_or_none(self.session, card_id=self.values[0])
# if human_batter_card is None:
# log_exception(CardNotFoundException, f'Card ID {self.values[0]} not found')
# if human_batter_card.team_id != self.team.id:
# logger.error(f'Card_id {self.values[0]} does not belong to {self.team.abbrev} in Game {self.game.id}')
# await interaction.channel.send(
# f'Uh oh. Card ID {self.values[0]} is {human_batter_card.player.name} and belongs to {human_batter_card.team.sname}. Will you double check that before we get started?'
# )
# return
# this_play = self.game.current_play_or_none(self.session)
# if this_play is None:
# log_exception(PlayNotFoundException, 'Play not found during substitution')
# logger.info(f'this_play: {this_play}')
# last_lineup = get_one_lineup(
# session=self.session,
# this_game=self.game,
# this_team=self.team,
# active=True,
# batting_order=self.batting_order
# )
# same_position = await ask_confirm(
# interaction,
# question=f'Will **{human_batter_card.player.name}** replace {last_lineup.player.name} as the {last_lineup.position}?',
# label_type='yes'
# )
# if same_position:
# position = last_lineup.position
# pos_text = ''
# view = None
# else:
# pos_dict_list = {
# 'Pinch Hitter': 'PH',
# 'Catcher': 'C',
# 'First Base': '1B',
# 'Second Base': '2B',
# 'Third Base': '3B',
# 'Shortstop': 'SS',
# 'Left Field': 'LF',
# 'Center Field': 'CF',
# 'Right Field': 'RF',
# 'Pinch Runner': 'PR',
# 'Pitcher': 'P'
# }
# position = 'PH'
# pos_text = 'What position will they play?'
# options=[SelectSubPosition(label=f'{x}', value=pos_dict_list[x], default=x=='Pinch Hitter') for x in pos_dict_list]
# view = DropdownView(dropdown_objects=options)
# last_lineup.active = False
# self.session.add(last_lineup)
# logger.info(f'Set {last_lineup.card.player.name_with_desc} as inactive')
# human_bat_lineup = Lineup(
# team=self.team,
# player=human_batter_card.player,
# card=human_batter_card,
# position=position,
# batting_order=self.batting_order,
# game=self.game,
# after_play=max(this_play.play_num - 1, 0),
# replacing_id=last_lineup.id
# )
# logger.info(f'new lineup: {human_bat_lineup}')
# self.session.add(human_bat_lineup)
# # self.session.commit()
# try:
# logger.info(f'Inserted {human_bat_lineup.card.player.name_with_desc} in the {self.batting_order} spot')
# this_play.batter = human_bat_lineup
# this_play.batter_pos = position
# except Exception as e:
# logger.error(e, exc_info=True, stack_info=True)
# self.session.add(this_play)
# self.session.commit()
# await interaction.edit_original_response(
# content=f'{human_batter_card.player.name_with_desc} has entered in the {self.batting_order} spot. {pos_text}',
# view=view
# )
class SelectPokemonEvolution(discord.ui.Select):
def __init__(self, *, placeholder = 'Evolve the selected Pokemon', min_values = 1, max_values = 1, options = List[SelectOption], this_team):
logging.info(f'Inside SelectPokemonEvolution init function')
self.team = this_team
super().__init__(placeholder=placeholder, min_values=min_values, max_values=max_values, options=options)
async def callback(self, interaction: discord.Interaction):
await interaction.response.defer()
try:
card_id = self.values[0]
this_card = await db_get(
'cards',
object_id=card_id,
none_okay=False
)
evo_mon = await db_get(
'players',
object_id=this_card['player']['fangr_id'],
none_okay=False
)
p_query = await db_post(
'packs/one',
payload={
'team_id': self.team['id'],
'pack_type_id': 4,
'open_time': datetime.datetime.timestamp(datetime.datetime.now()) * 1000}
)
pack_id = p_query['id']
await db_post(
'cards',
payload={'cards': [ {'player_id': evo_mon['player_id'], 'team_id': self.team['id'], 'pack_id': pack_id}]},
timeout=10
)
await interaction.edit_original_response(
content=f'## {this_card["player"]["p_name"].upper()} is evolving!',
embeds=await get_card_embeds(this_card),
view=None
)
await db_delete('cards', object_id=card_id)
await asyncio.sleep(3)
await interaction.channel.send(
content=f'## {this_card["player"]["p_name"].upper()} evolved into {evo_mon["p_name"].upper()}!',
embeds=await get_card_embeds({'team': self.team, 'player': evo_mon})
)
except Exception as e:
logging.error(f'Failed to evolve a pokemon: {e}', exc_info=True, stack_info=True)
await interaction.edit_original_response(content=f'Oh no, the evolution failed! Go ping the shit out of Cal so he can evolve it for you!')

21
utilities/embeds.py Normal file
View File

@ -0,0 +1,21 @@
import discord
from helpers import IMAGES, PD_SEASON, SBA_COLOR
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

45
utilities/pages.py Normal file
View File

@ -0,0 +1,45 @@
import discord
import logging
logger = logging.getLogger('discord_app')
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()