S10 Updates + PR Bugfix
This commit is contained in:
parent
80e94498fa
commit
0e3b98eb65
@ -421,22 +421,22 @@ class Economy(commands.Cog):
|
||||
embed.description = 'Cardset Requirements'
|
||||
embed.add_field(
|
||||
name='Ranked Legal',
|
||||
value='2024 Season + Promos, 2018 Season + Promos',
|
||||
value='2005, 2025 Seasons + Promos',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Minor League',
|
||||
value='Humans: Unlimited\nAI: 2024 Season / 2018 Season as backup',
|
||||
value='Humans: Unlimited\nAI: 2005 Season / 2025 Season as backup',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Major League',
|
||||
value='Humans: Ranked Legal\nAI: 2024, 2018, 2016, 2008 Seasons / 2023 & 2022 as backup',
|
||||
value='Humans: Ranked Legal\nAI: 2005, 2025, 2018, 2012 Seasons + Promos',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Flashback',
|
||||
value='2016, 2013, 2012, 2008 Seasons',
|
||||
value='2018, 2019, 2021, 2022 Seasons',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
|
||||
@ -211,22 +211,22 @@ class HelpSystem(commands.Cog):
|
||||
embed.description = 'Cardset Requirements'
|
||||
embed.add_field(
|
||||
name='Ranked Legal',
|
||||
value='2024 Season + Promos, 2018 Season + Promos',
|
||||
value='2005 Season + Promos, 2025 Season + Promos',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Minor League',
|
||||
value='Humans: Unlimited\nAI: 2024 Season / 2018 Season as backup',
|
||||
value='Humans: Unlimited\nAI: 2005 Season / 2025 Season as backup',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Major League',
|
||||
value='Humans: Ranked Legal\nAI: 2024, 2018, 2016, 2008 Seasons / 2023 & 2022 as backup',
|
||||
value='Humans: Ranked Legal\nAI: 2005, 2025, 2018, 2012 Seasons + Promos',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name='Flashback',
|
||||
value='2016, 2013, 2012, 2008 Seasons',
|
||||
value='2018, 2019, 2021, 2022 Seasons',
|
||||
inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
|
||||
@ -891,9 +891,10 @@ async def get_full_roster_from_sheets(session: Session, interaction: discord.Int
|
||||
try:
|
||||
card_ids = [row[0].value for row in raw_cells]
|
||||
logger.info(f'card_ids: {card_ids}')
|
||||
except ValueError as e:
|
||||
except (ValueError, TypeError) as e:
|
||||
logger.error(f'Could not pull roster for {this_team.abbrev}: {e}')
|
||||
log_exception(GoogleSheetsException, f'Uh oh. Looks like your roster might not be saved. I am reading blanks when I try to get the card IDs')
|
||||
logger.error(f'raw_cells type: {type(raw_cells)} / raw_cells: {raw_cells}')
|
||||
raise GoogleSheetsException(f'Uh oh. I had trouble reading your roster from Google Sheets (range {l_range}). Please make sure your roster is saved properly and all cells contain valid card IDs.')
|
||||
|
||||
for x in card_ids:
|
||||
this_card = await get_card_or_none(session, card_id=x)
|
||||
@ -978,6 +979,64 @@ def log_run_scored(session: Session, runner: Lineup, this_play: Play, is_earned:
|
||||
return True
|
||||
|
||||
|
||||
def create_pinch_runner_entry_play(session: Session, game: Game, current_play: Play, pinch_runner_lineup: Lineup) -> Play:
|
||||
"""
|
||||
Creates a "pinch runner entry" Play record when a pinch runner substitutes for a player on base.
|
||||
This Play has PA=0, AB=0 so it doesn't affect counting stats, but provides a record to mark
|
||||
when the pinch runner scores.
|
||||
|
||||
Commits the new Play.
|
||||
|
||||
Args:
|
||||
session: Database session
|
||||
game: The current game
|
||||
current_play: The current active Play (not yet complete)
|
||||
pinch_runner_lineup: The Lineup record for the pinch runner
|
||||
|
||||
Returns:
|
||||
The newly created entry Play
|
||||
"""
|
||||
logger.info(f'Creating pinch runner entry Play for {pinch_runner_lineup.player.name_with_desc} in Game {game.id}')
|
||||
|
||||
# Get the next play number
|
||||
max_play_num = session.exec(select(func.max(Play.play_num)).where(Play.game == game)).one()
|
||||
next_play_num = max_play_num + 1 if max_play_num else 1
|
||||
|
||||
# Create the entry Play
|
||||
entry_play = Play(
|
||||
game=game,
|
||||
play_num=next_play_num,
|
||||
batter=pinch_runner_lineup,
|
||||
pitcher=current_play.pitcher,
|
||||
catcher=current_play.catcher,
|
||||
inning_half=current_play.inning_half,
|
||||
inning_num=current_play.inning_num,
|
||||
batting_order=pinch_runner_lineup.batting_order,
|
||||
starting_outs=current_play.starting_outs,
|
||||
away_score=current_play.away_score,
|
||||
home_score=current_play.home_score,
|
||||
on_base_code=current_play.on_base_code,
|
||||
batter_pos=pinch_runner_lineup.position,
|
||||
# This is NOT a plate appearance
|
||||
pa=0,
|
||||
ab=0,
|
||||
run=0, # Will be set to 1 if they score
|
||||
# All other stats default to 0
|
||||
complete=True, # This "event" is complete
|
||||
is_tied=current_play.is_tied,
|
||||
is_go_ahead=False,
|
||||
is_new_inning=False,
|
||||
managerai_id=current_play.managerai_id
|
||||
)
|
||||
|
||||
session.add(entry_play)
|
||||
session.commit()
|
||||
session.refresh(entry_play)
|
||||
|
||||
logger.info(f'Created entry Play #{entry_play.play_num} for pinch runner {pinch_runner_lineup.player.name_with_desc}')
|
||||
return entry_play
|
||||
|
||||
|
||||
def advance_runners(session: Session, this_play: Play, num_bases: int, only_forced: bool = False, earned_bases: int = None) -> Play:
|
||||
"""
|
||||
No commits
|
||||
|
||||
54
constants.py
54
constants.py
@ -8,43 +8,42 @@ import discord
|
||||
from typing import Literal
|
||||
|
||||
# Season Configuration
|
||||
SBA_SEASON = 11
|
||||
PD_SEASON = 9
|
||||
ranked_cardsets = [20, 21, 22, 17, 18, 19]
|
||||
LIVE_CARDSET_ID = 24
|
||||
LIVE_PROMO_CARDSET_ID = 25
|
||||
SBA_SEASON = 12
|
||||
PD_SEASON = 10
|
||||
ranked_cardsets = [24, 25, 26, 27, 28, 29]
|
||||
LIVE_CARDSET_ID = 27
|
||||
LIVE_PROMO_CARDSET_ID = 28
|
||||
MAX_CARDSET_ID = 30
|
||||
|
||||
# Cardset Configuration
|
||||
CARDSETS = {
|
||||
'Ranked': {
|
||||
'ranked': {
|
||||
'primary': ranked_cardsets,
|
||||
'human': ranked_cardsets
|
||||
},
|
||||
'Minor League': {
|
||||
'primary': [20, 8], # 1998, Mario
|
||||
'secondary': [6], # 2013
|
||||
'human': [x for x in range(1, MAX_CARDSET_ID)]
|
||||
'minor-league': {
|
||||
'primary': [27, 8], # 2005, Mario
|
||||
'secondary': [24], # 2025
|
||||
'human': [x for x in range(1, 30)]
|
||||
},
|
||||
'Major League': {
|
||||
'primary': [20, 21, 17, 18, 12, 6, 7, 8], # 1998, 1998 Promos, 2024, 24 Promos, 2008, 2013, 2012, Mario
|
||||
'major-league': {
|
||||
'primary': [27, 28, 24, 25, 13, 14, 6, 8], # 2005 + Promos, 2025 + Promos, 2018 + Promos, 2012, Mario
|
||||
'secondary': [5, 3], # 2019, 2022
|
||||
'human': ranked_cardsets
|
||||
},
|
||||
'Hall of Fame': {
|
||||
'primary': [x for x in range(1, MAX_CARDSET_ID)],
|
||||
'secondary': [],
|
||||
'hall-of-fame': {
|
||||
'primary': [x for x in range(1, 30)],
|
||||
'human': ranked_cardsets
|
||||
},
|
||||
'Flashback': {
|
||||
'primary': [5, 1, 3, 9, 8], # 2019, 2021, 2022, 2023, Mario
|
||||
'secondary': [13, 5], # 2018, 2019
|
||||
'human': [5, 1, 3, 9, 8] # 2019, 2021, 2022, 2023
|
||||
'flashback': {
|
||||
'primary': [13, 5, 1, 3, 8], # 2018, 2019, 2021, 2022, Mario
|
||||
'secondary': [24], # 2025
|
||||
'human': [13, 5, 1, 3, 8] # 2018, 2019, 2021, 2022
|
||||
},
|
||||
'gauntlet-3': {
|
||||
'primary': [13], # 2018
|
||||
'secondary': [5, 11, 9], # 2019, 2016, 2023
|
||||
'human': [x for x in range(1, MAX_CARDSET_ID)]
|
||||
'human': [x for x in range(1, 30)]
|
||||
},
|
||||
'gauntlet-4': {
|
||||
'primary': [3, 6, 16], # 2022, 2013, Backyard Baseball
|
||||
@ -54,17 +53,26 @@ CARDSETS = {
|
||||
'gauntlet-5': {
|
||||
'primary': [17, 8], # 2024, Mario
|
||||
'secondary': [13], # 2018
|
||||
'human': [x for x in range(1, MAX_CARDSET_ID)]
|
||||
'human': [x for x in range(1, 30)]
|
||||
},
|
||||
'gauntlet-6': {
|
||||
'primary': [20, 8], # 1998, Mario
|
||||
'secondary': [12], # 2008
|
||||
'human': [x for x in range(1, MAX_CARDSET_ID)]
|
||||
'human': [x for x in range(1, 30)]
|
||||
},
|
||||
'gauntlet-7': {
|
||||
'primary': [5, 23], # 2019, Brilliant Stars
|
||||
'secondary': [1], # 2021
|
||||
'human': [x for x in range(1, MAX_CARDSET_ID)]
|
||||
'human': [x for x in range(1, 30)]
|
||||
},
|
||||
'gauntlet-8': {
|
||||
'primary': [24], # 2025
|
||||
'secondary': [17],
|
||||
'human': [24, 25, 22, 23]
|
||||
},
|
||||
'gauntlet-9': {
|
||||
'primary': [27], # 2005
|
||||
'secondary': [24] # 2025
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
gauntlets.py
18
gauntlets.py
@ -267,6 +267,24 @@ async def get_opponent(session: Session, this_team, this_event, this_run) -> Tea
|
||||
else:
|
||||
raise KeyError(f'Hmm...I do not know who you should be playing right now.')
|
||||
t_id = teams[random.randint(0, len(teams)-1)]
|
||||
elif this_event['id'] == 9:
|
||||
gp_to_tid = {
|
||||
0: 7,
|
||||
1: 4,
|
||||
2: 19,
|
||||
3: 22,
|
||||
4: 30,
|
||||
5: 3,
|
||||
6: 2,
|
||||
7: 1,
|
||||
8: 26,
|
||||
9: 20,
|
||||
10: 6
|
||||
}
|
||||
try:
|
||||
t_id = gp_to_tid[gp]
|
||||
except KeyError:
|
||||
raise KeyError(f'Hmm...I do not know who you should be playing with {gp} games played.')
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@ HELP_NEWGAME = (
|
||||
|
||||
|
||||
HELP_PLAYGAME = (
|
||||
f'- Run `!help Dice` to see all roll commands available; `!ab` is the one you will roll for every at bat\n'
|
||||
f'- Run `/gamestate` for the current scorebug and click the Roll AB button\n'
|
||||
f'- Log results with `/log <play-data>`; all results on the card should be represented, some have '
|
||||
f'nested commands (e.g. `/log flyball b`)\n'
|
||||
f'- When you mess up a result, run `/log undo-play` and it will roll back one play\n'
|
||||
@ -100,13 +100,13 @@ HELP_TS_MENU = (
|
||||
|
||||
HELP_REWARDS_PREMIUM = (
|
||||
'- Win a 9-inning game\n'
|
||||
'- Purchasable for 200₼\n'
|
||||
'- Purchasable for 300₼\n'
|
||||
'- Purchasable for $3 on the ko-fi shop'
|
||||
)
|
||||
|
||||
HELP_REWARDS_STANDARD = (
|
||||
'- Win a 3-inning game\n'
|
||||
'- Purchasable for 100₼\n'
|
||||
'- Purchasable for 200₼\n'
|
||||
'- Every fifth check-in (`/comeonmanineedthis`)\n'
|
||||
'- Purchasable for $2 on the ko-fi shop'
|
||||
)
|
||||
@ -146,5 +146,5 @@ HELP_START_PLAY = (
|
||||
)
|
||||
|
||||
HELP_START_ASK = (
|
||||
f'Feel free to ask any questions down in '
|
||||
f'Feel free to ask any questions down in #paper-dynasty-chat'
|
||||
)
|
||||
|
||||
148
manual_pack_distribution.py
Normal file
148
manual_pack_distribution.py
Normal file
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Manual script to distribute packs to all human-controlled teams
|
||||
"""
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from api_calls import db_get, db_post, DB_URL
|
||||
|
||||
# Set up logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger('manual_pack_dist')
|
||||
|
||||
|
||||
def check_environment():
|
||||
"""Check that required environment variables are set"""
|
||||
api_token = os.getenv('API_TOKEN')
|
||||
database_env = os.getenv('DATABASE', 'dev')
|
||||
|
||||
if not api_token:
|
||||
logger.error("ERROR: API_TOKEN environment variable is not set!")
|
||||
logger.error("Please set it with: export API_TOKEN='your-token-here'")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info(f"Using database environment: {database_env}")
|
||||
logger.info(f"API URL: {DB_URL}")
|
||||
logger.info(f"API Token: {'*' * (len(api_token) - 4)}{api_token[-4:] if len(api_token) > 4 else '****'}")
|
||||
logger.info("")
|
||||
|
||||
|
||||
async def distribute_packs(num_packs: int = 5, exclude_team_abbrev: list[str] = None):
|
||||
"""Distribute packs to all human-controlled teams
|
||||
|
||||
Args:
|
||||
num_packs: Number of packs to give to each team (default: 5)
|
||||
exclude_team_abbrev: List of team abbreviations to exclude (default: None)
|
||||
"""
|
||||
if exclude_team_abbrev is None:
|
||||
exclude_team_abbrev = []
|
||||
|
||||
# Convert to uppercase for case-insensitive matching
|
||||
exclude_team_abbrev = [abbrev.upper() for abbrev in exclude_team_abbrev]
|
||||
|
||||
# Step 1: Get current season
|
||||
logger.info("Fetching current season...")
|
||||
current = await db_get('current')
|
||||
if current is None:
|
||||
logger.error("Failed to fetch current season from API. Check your API_TOKEN and DATABASE environment variables.")
|
||||
logger.error(f"API URL: {DB_URL}")
|
||||
logger.error("Make sure the API endpoint is accessible and your token is valid.")
|
||||
raise ValueError("Could not connect to the database API")
|
||||
|
||||
logger.info(f"Current season: {current['season']}")
|
||||
|
||||
# Step 2: Get all teams for current season
|
||||
logger.info(f"Fetching all teams for season {current['season']}...")
|
||||
all_teams = await db_get('teams', params=[('season', current['season'])])
|
||||
if all_teams is None:
|
||||
logger.error("Failed to fetch teams from API")
|
||||
raise ValueError("Could not fetch teams from the database API")
|
||||
|
||||
logger.info(f"Found {all_teams['count']} total teams")
|
||||
|
||||
# Step 3: Filter for human-controlled teams only
|
||||
qualifying_teams = []
|
||||
for team in all_teams['teams']:
|
||||
if not team['is_ai'] and 'gauntlet' not in team['abbrev'].lower():
|
||||
# Check if team is in exclusion list
|
||||
if team['abbrev'].upper() in exclude_team_abbrev:
|
||||
logger.info(f" - {team['abbrev']}: {team['sname']} (EXCLUDED)")
|
||||
continue
|
||||
qualifying_teams.append(team)
|
||||
logger.info(f" - {team['abbrev']}: {team['sname']}")
|
||||
|
||||
logger.info(f"\nFound {len(qualifying_teams)} human-controlled teams")
|
||||
if exclude_team_abbrev:
|
||||
logger.info(f"Excluded teams: {', '.join(exclude_team_abbrev)}")
|
||||
|
||||
# Step 4: Distribute packs
|
||||
pack_type_id = 1 # Standard packs
|
||||
|
||||
logger.info(f"\nDistributing {num_packs} standard packs to each team...")
|
||||
|
||||
for team in qualifying_teams:
|
||||
logger.info(f"Giving {num_packs} packs to {team['abbrev']} ({team['sname']})...")
|
||||
|
||||
# Create pack payload
|
||||
pack_payload = {
|
||||
'packs': [{
|
||||
'team_id': team['id'],
|
||||
'pack_type_id': pack_type_id,
|
||||
'pack_cardset_id': None
|
||||
} for _ in range(num_packs)]
|
||||
}
|
||||
|
||||
try:
|
||||
result = await db_post('packs', payload=pack_payload)
|
||||
logger.info(f" ✓ Successfully gave packs to {team['abbrev']}")
|
||||
except Exception as e:
|
||||
logger.error(f" ✗ Failed to give packs to {team['abbrev']}: {e}")
|
||||
|
||||
logger.info(f"\n🎉 All done! Distributed {num_packs} packs to {len(qualifying_teams)} teams")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Distribute packs to all human-controlled teams',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# Give 5 packs to all teams (default)
|
||||
python manual_pack_distribution.py
|
||||
|
||||
# Give 10 packs to all teams
|
||||
python manual_pack_distribution.py --num-packs 10
|
||||
|
||||
# Give 5 packs, excluding certain teams
|
||||
python manual_pack_distribution.py --exclude-team-abbrev NYY BOS
|
||||
|
||||
# Give 3 packs, excluding one team
|
||||
python manual_pack_distribution.py --num-packs 3 --exclude-team-abbrev LAD
|
||||
|
||||
Environment Variables:
|
||||
API_TOKEN - Required: API authentication token
|
||||
DATABASE - Optional: 'dev' (default) or 'prod'
|
||||
"""
|
||||
)
|
||||
parser.add_argument(
|
||||
'--num-packs',
|
||||
type=int,
|
||||
default=5,
|
||||
help='Number of packs to give to each team (default: 5)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--exclude-team-abbrev',
|
||||
nargs='*',
|
||||
default=[],
|
||||
help='Team abbreviations to exclude (space-separated, e.g., NYY BOS LAD)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Check environment before running
|
||||
check_environment()
|
||||
|
||||
asyncio.run(distribute_packs(num_packs=args.num_packs, exclude_team_abbrev=args.exclude_team_abbrev))
|
||||
@ -456,7 +456,8 @@ class SelectBatterSub(discord.ui.Select):
|
||||
try:
|
||||
last_lineup.active = False
|
||||
self.session.add(last_lineup)
|
||||
logger.info(f'Set {last_lineup.card.player.name_with_desc} as inactive')
|
||||
self.session.flush() # Flush to ensure the change is applied
|
||||
logger.info(f'Set lineup ID {last_lineup.id} as inactive')
|
||||
except Exception as e:
|
||||
log_exception(e)
|
||||
|
||||
@ -487,25 +488,42 @@ class SelectBatterSub(discord.ui.Select):
|
||||
self.session.add(human_bat_lineup)
|
||||
# self.session.commit()
|
||||
|
||||
logger.info(f'Inserted {human_bat_lineup.card.player.name_with_desc} in the {self.batting_order} spot')
|
||||
logger.info(f'Inserted player {human_batter_card.player_id} (card {human_batter_card.id}) in the {self.batting_order} spot')
|
||||
is_pinch_runner = False
|
||||
if this_play.batter == last_lineup:
|
||||
logger.info(f'Setting new sub to current play batter')
|
||||
this_play.batter = human_bat_lineup
|
||||
this_play.batter_pos = position
|
||||
elif this_play.on_first == last_lineup:
|
||||
logger.info(f'Setting new sub to run at first')
|
||||
logger.info(f'Setting new sub to run at first - this is a pinch runner')
|
||||
this_play.on_first = human_bat_lineup
|
||||
is_pinch_runner = True
|
||||
elif this_play.on_second == last_lineup:
|
||||
logger.info(f'Setting new sub to run at second')
|
||||
logger.info(f'Setting new sub to run at second - this is a pinch runner')
|
||||
this_play.on_second = human_bat_lineup
|
||||
is_pinch_runner = True
|
||||
elif this_play.on_third == last_lineup:
|
||||
logger.info(f'Setting new sub to run at third')
|
||||
logger.info(f'Setting new sub to run at third - this is a pinch runner')
|
||||
this_play.on_third = human_bat_lineup
|
||||
is_pinch_runner = True
|
||||
|
||||
logger.info(f'Adding play to session: {this_play}')
|
||||
self.session.add(this_play)
|
||||
self.session.commit()
|
||||
|
||||
# If this is a pinch runner, create an entry Play record for them
|
||||
if is_pinch_runner:
|
||||
# Import inside function to avoid circular import
|
||||
from command_logic.logic_gameplay import create_pinch_runner_entry_play
|
||||
|
||||
logger.info(f'Creating pinch runner entry Play for {human_bat_lineup.player.name_with_desc}')
|
||||
create_pinch_runner_entry_play(
|
||||
session=self.session,
|
||||
game=self.game,
|
||||
current_play=this_play,
|
||||
pinch_runner_lineup=human_bat_lineup
|
||||
)
|
||||
|
||||
# if not same_position:
|
||||
# pos_dict_list = {
|
||||
# 'Pinch Hitter': 'PH',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user