497 lines
21 KiB
Python
497 lines
21 KiB
Python
"""
|
|
Create custom card for Kalin Young
|
|
All-fields outfielder with low pull rate (25%) and 0.820 OPS target
|
|
"""
|
|
|
|
import asyncio
|
|
from custom_cards.archetype_definitions import BatterArchetype
|
|
from custom_cards.archetype_calculator import BatterRatingCalculator, calculate_total_ops
|
|
from creation_helpers import mlbteam_and_franchise
|
|
from db_calls import db_get, db_post, db_put, db_patch
|
|
from datetime import datetime
|
|
import boto3
|
|
import random
|
|
|
|
# AWS Configuration
|
|
AWS_BUCKET_NAME = 'paper-dynasty'
|
|
AWS_REGION = 'us-east-1'
|
|
S3_BASE_URL = f'https://{AWS_BUCKET_NAME}.s3.{AWS_REGION}.amazonaws.com'
|
|
|
|
|
|
async def create_kalin_young():
|
|
"""Create Kalin Young custom card."""
|
|
|
|
print("="*70)
|
|
print("CREATING KALIN YOUNG")
|
|
print("="*70)
|
|
|
|
# Player details
|
|
name_first = "Kalin"
|
|
name_last = "Young"
|
|
hand = "R" # Right-handed batter (assuming, can adjust if needed)
|
|
team_abbrev = "SEA" # Placeholder team
|
|
positions = ["RF", "LF"] # Outfielder
|
|
|
|
# Get team info
|
|
mlb_team_id, franchise_id = mlbteam_and_franchise(team_abbrev)
|
|
|
|
# Cardset setup - Always use cardset 29 for custom characters
|
|
cardset_id = 29
|
|
cardset = {'id': cardset_id, 'name': 'Custom Characters'}
|
|
season = 2005
|
|
player_description = "05 Custom"
|
|
print(f"✓ Using cardset ID: {cardset['id']} - Player description: '{player_description}'")
|
|
|
|
# Create custom archetype for Kalin Young
|
|
# Target: Combined OPS = 0.820 with formula: (OPS_vR + OPS_vL + min) / 3
|
|
# Calibrated to hit exact target after archetype calculator processing
|
|
|
|
kalin_young = BatterArchetype(
|
|
name="Kalin Young",
|
|
description="All-fields outfielder with low pull rate, balanced contact and power",
|
|
|
|
# VS RHP: Target OPS = 0.780 (OBP 0.320 + SLG 0.460) - aiming low for 0.820 output
|
|
avg_vs_r=0.240, # Good average
|
|
obp_vs_r=0.315, # Solid OBP
|
|
slg_vs_r=0.435, # Decent power
|
|
bb_pct_vs_r=0.09, # Moderate walks
|
|
k_pct_vs_r=0.21, # Decent contact
|
|
|
|
# VS LHP: Target OPS = 0.795 (OBP 0.330 + SLG 0.465) - aiming low for 0.820 output
|
|
avg_vs_l=0.250, # Better average vs L
|
|
obp_vs_l=0.325, # Better OBP
|
|
slg_vs_l=0.445, # More power vs L
|
|
bb_pct_vs_l=0.09, # Similar walks
|
|
k_pct_vs_l=0.20, # Slightly better contact vs L
|
|
|
|
# Power distribution - moderate power, balanced
|
|
hr_per_hit=0.09, # Moderate HR rate
|
|
triple_per_hit=0.03, # Some triples (outfield speed)
|
|
double_per_hit=0.26, # Good gap power
|
|
# Singles = 62% of hits
|
|
|
|
# Batted ball profile - balanced
|
|
gb_pct=0.43, # Moderate ground balls
|
|
fb_pct=0.34, # Moderate fly balls
|
|
ld_pct=0.23, # Line drives
|
|
|
|
# Batted ball quality
|
|
hard_pct=0.36, # Good hard contact
|
|
med_pct=0.46, # Lots of medium contact
|
|
soft_pct=0.18, # Some soft contact
|
|
|
|
# Spray chart - LOW PULL RATE (25%)
|
|
pull_pct=0.25, # Low pull (per requirements)
|
|
center_pct=0.40, # High center usage
|
|
oppo_pct=0.35, # Good opposite field usage
|
|
|
|
# Infield hits
|
|
ifh_pct=0.07, # Moderate speed for infield hits
|
|
|
|
# Specific power metrics
|
|
hr_fb_pct=0.11, # Moderate HR/FB
|
|
|
|
# Baserunning - good speed
|
|
speed_rating=6, # Above average speed
|
|
steal_jump=6, # Good reads
|
|
xbt_pct=0.53, # Takes extra bases
|
|
|
|
# Situational hitting
|
|
hit_run_skill=7, # Good contact = good hit-and-run
|
|
|
|
# Defensive profile
|
|
primary_positions=["RF", "LF"],
|
|
defensive_rating=6, # Above average defender
|
|
)
|
|
|
|
print(f"\n✓ Created custom archetype: {kalin_young.name}")
|
|
print(f" Base stats vR: {kalin_young.avg_vs_r:.3f}/{kalin_young.obp_vs_r:.3f}/{kalin_young.slg_vs_r:.3f} (OPS: {kalin_young.obp_vs_r + kalin_young.slg_vs_r:.3f})")
|
|
print(f" Base stats vL: {kalin_young.avg_vs_l:.3f}/{kalin_young.obp_vs_l:.3f}/{kalin_young.slg_vs_l:.3f} (OPS: {kalin_young.obp_vs_l + kalin_young.slg_vs_l:.3f})")
|
|
|
|
# Calculate ratings
|
|
calc = BatterRatingCalculator(kalin_young)
|
|
ratings = calc.calculate_ratings(battingcard_id=0) # Temp ID
|
|
baserunning = calc.calculate_baserunning()
|
|
|
|
# Override steal rate to 0.0833333 (15-7) - very low steal success
|
|
print(f"\n✓ Setting steal rate to 0.0833333 (15-7)...")
|
|
baserunning['steal_jump'] = 0.0833333
|
|
baserunning['steal_high'] = 15
|
|
baserunning['steal_low'] = 7
|
|
|
|
# Override running to 13
|
|
print(f"✓ Setting running to 13...")
|
|
baserunning['running'] = 13
|
|
|
|
# Apply randomization to make results look more natural
|
|
print(f"\n✓ Applying randomization (±0.5) and rounding to 0.05...")
|
|
random.seed(42) # For reproducibility
|
|
|
|
for rating in ratings:
|
|
# Fields to randomize (exclude exact targets)
|
|
randomize_fields = [
|
|
'homerun', 'bp_homerun', 'triple', 'double_three', 'double_two', 'double_pull',
|
|
'single_two', 'single_one', 'single_center',
|
|
'walk', 'hbp', 'strikeout', 'lineout', 'popout',
|
|
'flyout_a', 'flyout_bq', 'flyout_lf_b', 'flyout_rf_b',
|
|
'groundout_a', 'groundout_b', 'groundout_c'
|
|
]
|
|
|
|
for field in randomize_fields:
|
|
if rating[field] > 0: # Only randomize non-zero values
|
|
randomization = random.uniform(-0.5, 0.5)
|
|
new_value = rating[field] + randomization
|
|
# Round to nearest 0.05
|
|
rating[field] = round(new_value * 20) / 20
|
|
# Ensure non-negative
|
|
rating[field] = max(0.05, rating[field])
|
|
|
|
# Fix BP-HR and HBP to whole numbers (CRITICAL RULE)
|
|
print(f"\n✓ Setting BP-HR to whole numbers (2 vL, 1 vR)...")
|
|
print(f"✓ Setting HBP to whole numbers (1 both splits)...")
|
|
print(f"✓ Removing Triple vL...")
|
|
|
|
# vs LHP (ratings[0])
|
|
old_bphr_vl = ratings[0]['bp_homerun']
|
|
ratings[0]['bp_homerun'] = 2.0
|
|
# Redistribute difference to single_center
|
|
ratings[0]['single_center'] += (old_bphr_vl - 2.0)
|
|
|
|
old_hbp_vl = ratings[0]['hbp']
|
|
ratings[0]['hbp'] = 1.0
|
|
# Redistribute difference to single_center
|
|
ratings[0]['single_center'] += (old_hbp_vl - 1.0)
|
|
|
|
# Remove triple vL
|
|
old_triple_vl = ratings[0]['triple']
|
|
ratings[0]['triple'] = 0.0
|
|
# Redistribute to singles
|
|
ratings[0]['single_center'] += old_triple_vl
|
|
|
|
# vs RHP (ratings[1])
|
|
old_bphr_vr = ratings[1]['bp_homerun']
|
|
ratings[1]['bp_homerun'] = 1.0
|
|
# Redistribute difference to single_center
|
|
ratings[1]['single_center'] += (old_bphr_vr - 1.0)
|
|
|
|
old_hbp_vr = ratings[1]['hbp']
|
|
ratings[1]['hbp'] = 1.0
|
|
# Redistribute difference to single_center
|
|
ratings[1]['single_center'] += (old_hbp_vr - 1.0)
|
|
|
|
# Fix total chances to exactly 108.0
|
|
for rating in ratings:
|
|
total = sum([
|
|
rating['homerun'], rating['bp_homerun'], rating['triple'],
|
|
rating['double_three'], rating['double_two'], rating['double_pull'],
|
|
rating['single_two'], rating['single_one'], rating['single_center'], rating['bp_single'],
|
|
rating['walk'], rating['hbp'], rating['strikeout'], rating['lineout'], rating['popout'],
|
|
rating['flyout_a'], rating['flyout_bq'], rating['flyout_lf_b'], rating['flyout_rf_b'],
|
|
rating['groundout_a'], rating['groundout_b'], rating['groundout_c']
|
|
])
|
|
diff = 108.0 - total
|
|
if abs(diff) > 0.01:
|
|
# Add/subtract the difference to groundout_b (most common out type)
|
|
rating['groundout_b'] += diff
|
|
rating['groundout_b'] = round(rating['groundout_b'] * 20) / 20
|
|
|
|
# Recalculate rate stats (BP results multiply by 0.5 for AVG/OBP only)
|
|
for rating in ratings:
|
|
total_hits = (
|
|
rating['homerun'] + rating['bp_homerun'] * 0.5 + rating['triple'] +
|
|
rating['double_three'] + rating['double_two'] + rating['double_pull'] +
|
|
rating['single_two'] + rating['single_one'] + rating['single_center'] + rating['bp_single'] * 0.5
|
|
)
|
|
rating['avg'] = round(total_hits / 108, 5)
|
|
rating['obp'] = round((total_hits + rating['hbp'] + rating['walk']) / 108, 5)
|
|
# SLG: BP-HR gets 2 bases, BP-1B gets 1 base
|
|
rating['slg'] = round((
|
|
rating['homerun'] * 4 + rating['bp_homerun'] * 2 +
|
|
rating['triple'] * 3 +
|
|
(rating['double_two'] + rating['double_three'] + rating['double_pull']) * 2 +
|
|
rating['single_center'] + rating['single_two'] + rating['single_one'] + rating['bp_single']
|
|
) / 108, 5)
|
|
|
|
# Display adjusted ratings
|
|
print("\n" + "="*70)
|
|
print("FINAL RATINGS (TWO-COLUMN TABLE)")
|
|
print("="*70)
|
|
|
|
# Two-column table display
|
|
vl = ratings[0] # vs LHP
|
|
vr = ratings[1] # vs RHP
|
|
|
|
print(f"\n{'RATING':<25} {'VS LHP':>12} {'VS RHP':>12}")
|
|
print("-" * 50)
|
|
print(f"{'AVG':<25} {vl['avg']:>12.3f} {vr['avg']:>12.3f}")
|
|
print(f"{'OBP':<25} {vl['obp']:>12.3f} {vr['obp']:>12.3f}")
|
|
print(f"{'SLG':<25} {vl['slg']:>12.3f} {vr['slg']:>12.3f}")
|
|
print(f"{'OPS':<25} {vl['obp']+vl['slg']:>12.3f} {vr['obp']+vr['slg']:>12.3f}")
|
|
print()
|
|
print(f"{'HITS':<25}")
|
|
print(f"{' Homerun':<25} {vl['homerun']:>12.1f} {vr['homerun']:>12.1f}")
|
|
print(f"{' BP Homerun':<25} {vl['bp_homerun']:>12.1f} {vr['bp_homerun']:>12.1f}")
|
|
print(f"{' Triple':<25} {vl['triple']:>12.1f} {vr['triple']:>12.1f}")
|
|
print(f"{' Double (3B)':<25} {vl['double_three']:>12.1f} {vr['double_three']:>12.1f}")
|
|
print(f"{' Double (2B)':<25} {vl['double_two']:>12.1f} {vr['double_two']:>12.1f}")
|
|
print(f"{' Double (Pull)':<25} {vl['double_pull']:>12.1f} {vr['double_pull']:>12.1f}")
|
|
print(f"{' Single (2B)':<25} {vl['single_two']:>12.1f} {vr['single_two']:>12.1f}")
|
|
print(f"{' Single (1B)':<25} {vl['single_one']:>12.1f} {vr['single_one']:>12.1f}")
|
|
print(f"{' Single (Center)':<25} {vl['single_center']:>12.1f} {vr['single_center']:>12.1f}")
|
|
print(f"{' BP Single':<25} {vl['bp_single']:>12.1f} {vr['bp_single']:>12.1f}")
|
|
print()
|
|
print(f"{'ON-BASE':<25}")
|
|
print(f"{' Walk':<25} {vl['walk']:>12.1f} {vr['walk']:>12.1f}")
|
|
print(f"{' HBP':<25} {vl['hbp']:>12.1f} {vr['hbp']:>12.1f}")
|
|
print()
|
|
print(f"{'OUTS':<25}")
|
|
print(f"{' Strikeout':<25} {vl['strikeout']:>12.1f} {vr['strikeout']:>12.1f}")
|
|
print(f"{' Lineout':<25} {vl['lineout']:>12.1f} {vr['lineout']:>12.1f}")
|
|
print(f"{' Popout':<25} {vl['popout']:>12.1f} {vr['popout']:>12.1f}")
|
|
print(f"{' Flyout A':<25} {vl['flyout_a']:>12.1f} {vr['flyout_a']:>12.1f}")
|
|
print(f"{' Flyout BQ':<25} {vl['flyout_bq']:>12.1f} {vr['flyout_bq']:>12.1f}")
|
|
print(f"{' Flyout LF B':<25} {vl['flyout_lf_b']:>12.1f} {vr['flyout_lf_b']:>12.1f}")
|
|
print(f"{' Flyout RF B':<25} {vl['flyout_rf_b']:>12.1f} {vr['flyout_rf_b']:>12.1f}")
|
|
print(f"{' Groundout A':<25} {vl['groundout_a']:>12.1f} {vr['groundout_a']:>12.1f}")
|
|
print(f"{' Groundout B':<25} {vl['groundout_b']:>12.1f} {vr['groundout_b']:>12.1f}")
|
|
print(f"{' Groundout C':<25} {vl['groundout_c']:>12.1f} {vr['groundout_c']:>12.1f}")
|
|
print()
|
|
print(f"{'SPRAY CHART':<25}")
|
|
print(f"{' Pull %':<25} {vl['pull_rate']:>11.1%} {vr['pull_rate']:>11.1%}")
|
|
print(f"{' Center %':<25} {vl['center_rate']:>11.1%} {vr['center_rate']:>11.1%}")
|
|
print(f"{' Opposite %':<25} {vl['slap_rate']:>11.1%} {vr['slap_rate']:>11.1%}")
|
|
print()
|
|
|
|
# Calculate totals
|
|
total_vl = sum([
|
|
vl['homerun'], vl['bp_homerun'], vl['triple'],
|
|
vl['double_three'], vl['double_two'], vl['double_pull'],
|
|
vl['single_two'], vl['single_one'], vl['single_center'], vl['bp_single'],
|
|
vl['walk'], vl['hbp'], vl['strikeout'], vl['lineout'], vl['popout'],
|
|
vl['flyout_a'], vl['flyout_bq'], vl['flyout_lf_b'], vl['flyout_rf_b'],
|
|
vl['groundout_a'], vl['groundout_b'], vl['groundout_c']
|
|
])
|
|
total_vr = sum([
|
|
vr['homerun'], vr['bp_homerun'], vr['triple'],
|
|
vr['double_three'], vr['double_two'], vr['double_pull'],
|
|
vr['single_two'], vr['single_one'], vr['single_center'], vr['bp_single'],
|
|
vr['walk'], vr['hbp'], vr['strikeout'], vr['lineout'], vr['popout'],
|
|
vr['flyout_a'], vr['flyout_bq'], vr['flyout_lf_b'], vr['flyout_rf_b'],
|
|
vr['groundout_a'], vr['groundout_b'], vr['groundout_c']
|
|
])
|
|
print(f"{'TOTAL CHANCES':<25} {total_vl:>12.1f} {total_vr:>12.1f}")
|
|
print("-" * 50)
|
|
|
|
# Calculate and display total OPS
|
|
total_ops = calculate_total_ops(ratings[0], ratings[1], is_pitcher=False)
|
|
print(f"\nTotal OPS: {total_ops:.3f} (Target: 0.820)")
|
|
|
|
print(f"\nBaserunning:")
|
|
print(f" Steal: {baserunning['steal_low']}-{baserunning['steal_high']} (Auto: {baserunning['steal_auto']}, Jump: {baserunning['steal_jump']})")
|
|
print(f" Running: {baserunning['running']} Hit-and-Run: {baserunning['hit_and_run']}")
|
|
|
|
# Summary
|
|
print("\n" + "="*70)
|
|
print("SUMMARY")
|
|
print("="*70)
|
|
print(f"\nPlayer: Kalin Young ({hand})")
|
|
print(f"Positions: RF (primary), LF (secondary)")
|
|
print(f"Cardset: 29 (Custom Characters)")
|
|
print(f"Description: 05 Custom")
|
|
print(f"Total OPS: {total_ops:.3f} / 0.820 target")
|
|
print(f"Pull Rate: ~{vl['pull_rate']*100:.0f}%/{vr['pull_rate']*100:.0f}% (Target: 25%)")
|
|
|
|
print("\n" + "="*70)
|
|
print("DATABASE CREATION")
|
|
print("="*70)
|
|
|
|
# Set bunting to C (average)
|
|
baserunning['bunting'] = 'C'
|
|
print(f"\n✓ Bunting set to: C")
|
|
|
|
# Create database records
|
|
bbref_id = f"custom_{name_last.lower()}{name_first[0].lower()}01"
|
|
|
|
# Step 1: Create/verify MLBPlayer record
|
|
print(f"\n✓ Checking for existing MLBPlayer record...")
|
|
mlb_query = await db_get('mlbplayers', params=[('first_name', name_first), ('last_name', name_last)])
|
|
if mlb_query and mlb_query.get('count', 0) > 0:
|
|
mlbplayer_id = mlb_query['players'][0]['id']
|
|
print(f" Using existing MLBPlayer ID: {mlbplayer_id}")
|
|
else:
|
|
try:
|
|
mlbplayer_payload = {
|
|
'key_bbref': bbref_id,
|
|
'key_fangraphs': 0,
|
|
'key_mlbam': 0,
|
|
'key_retro': '',
|
|
'first_name': name_first,
|
|
'last_name': name_last,
|
|
}
|
|
new_mlbplayer = await db_post('mlbplayers/one', payload=mlbplayer_payload)
|
|
mlbplayer_id = new_mlbplayer['id']
|
|
print(f" Created MLBPlayer ID: {mlbplayer_id}")
|
|
except ValueError as e:
|
|
print(f" MLBPlayer creation failed: {e}")
|
|
print(f" Proceeding without MLBPlayer linkage...")
|
|
mlbplayer_id = None
|
|
|
|
# Step 2: Create or update Player record
|
|
print(f"\n✓ Checking for existing Player record...")
|
|
now = datetime.now()
|
|
release_date = f"{now.year}-{now.month}-{now.day}"
|
|
|
|
# Check if player already exists
|
|
p_query = await db_get('players', params=[('bbref_id', bbref_id), ('cardset_id', cardset['id'])])
|
|
if p_query and p_query.get('count', 0) > 0:
|
|
player_id = p_query['players'][0]['player_id']
|
|
print(f" Using existing Player ID: {player_id}")
|
|
# Update the image URL
|
|
image_url = f"https://pd.manticorum.com/api/v2/players/{player_id}/battingcard?d={release_date}"
|
|
await db_patch('players', object_id=player_id, params=[('image', image_url)])
|
|
print(f" Updated image URL")
|
|
else:
|
|
# Create new player
|
|
print(f" Creating new Player record...")
|
|
temp_image_url = f"https://pd.manticorum.com/api/v2/players/0/battingcard?d={release_date}"
|
|
|
|
player_payload = {
|
|
'p_name': f"{name_first} {name_last}",
|
|
'bbref_id': bbref_id,
|
|
'fangr_id': 0,
|
|
'strat_code': 0,
|
|
'hand': hand,
|
|
'mlbclub': 'Custom Ballplayers',
|
|
'franchise': 'Custom Ballplayers',
|
|
'cardset_id': cardset['id'],
|
|
'description': player_description,
|
|
'is_custom': True,
|
|
'cost': 100, # Placeholder
|
|
'rarity_id': 5, # Common placeholder
|
|
'image': temp_image_url,
|
|
'set_num': 9999, # Custom player set number
|
|
'pos_1': 'RF', # Primary position
|
|
'pos_2': 'LF', # Secondary position
|
|
}
|
|
|
|
if mlbplayer_id:
|
|
player_payload['mlbplayer_id'] = mlbplayer_id
|
|
|
|
new_player = await db_post('players', payload=player_payload)
|
|
player_id = new_player['player_id']
|
|
print(f" Created Player ID: {player_id}")
|
|
|
|
# Update with correct image URL
|
|
image_url = f"https://pd.manticorum.com/api/v2/players/{player_id}/battingcard?d={release_date}"
|
|
await db_patch('players', object_id=player_id, params=[('image', image_url)])
|
|
print(f" Updated with correct image URL")
|
|
|
|
# Step 3: Create BattingCard
|
|
print(f"\n✓ Creating BattingCard...")
|
|
batting_card_payload = {
|
|
'cards': [{
|
|
'player_id': player_id,
|
|
'key_bbref': bbref_id,
|
|
'key_fangraphs': 0,
|
|
'key_mlbam': 0,
|
|
'key_retro': '',
|
|
'name_first': name_first,
|
|
'name_last': name_last,
|
|
'steal_low': baserunning['steal_low'],
|
|
'steal_high': baserunning['steal_high'],
|
|
'steal_auto': baserunning['steal_auto'],
|
|
'steal_jump': baserunning['steal_jump'],
|
|
'hit_and_run': baserunning['hit_and_run'],
|
|
'running': baserunning['running'],
|
|
'hand': hand,
|
|
'bunting': baserunning['bunting'],
|
|
}]
|
|
}
|
|
|
|
await db_put('battingcards', payload=batting_card_payload, timeout=10)
|
|
print(f" BattingCard created")
|
|
|
|
# Get the created card ID
|
|
bc_query = await db_get('battingcards', params=[('player_id', player_id)])
|
|
battingcard_id = bc_query['cards'][0]['id']
|
|
print(f" BattingCard ID: {battingcard_id}")
|
|
|
|
# Step 4: Create BattingCardRatings
|
|
print(f"\n✓ Creating BattingCardRatings...")
|
|
for rating in ratings:
|
|
rating['battingcard_id'] = battingcard_id
|
|
|
|
ratings_payload = {'ratings': ratings}
|
|
await db_put('battingcardratings', payload=ratings_payload, timeout=10)
|
|
print(f" Ratings created (vL and vR)")
|
|
|
|
# Step 5: Create CardPositions with defensive ratings
|
|
print(f"\n✓ Creating CardPositions...")
|
|
positions_payload = {
|
|
'positions': [
|
|
{
|
|
'player_id': player_id,
|
|
'variant': 0,
|
|
'position': 'RF',
|
|
'innings': 1,
|
|
'range': 3, # Range 3
|
|
'error': 7, # Error 7
|
|
'arm': 0, # Arm 0
|
|
},
|
|
{
|
|
'player_id': player_id,
|
|
'variant': 0,
|
|
'position': 'LF',
|
|
'innings': 1,
|
|
'range': 4, # Range 4
|
|
'error': 7, # Error 7
|
|
'arm': 0, # Arm 0
|
|
}
|
|
]
|
|
}
|
|
|
|
await db_put('cardpositions', payload=positions_payload, timeout=10)
|
|
print(f" Positions created:")
|
|
print(f" RF: Range 3, Error 7, Arm 0")
|
|
print(f" LF: Range 4, Error 7, Arm 0")
|
|
|
|
# Step 6: Update rarity and cost (will be calculated based on OPS)
|
|
print(f"\n✓ Updating rarity and cost...")
|
|
# For 0.820 OPS, this is around Starter/All-Star range
|
|
# Let's use Starter (rarity 3) with cost based on OPS
|
|
target_rarity_id = 3 # Starter
|
|
target_cost = 85 # Approximate for 0.820 OPS
|
|
|
|
await db_patch('players', object_id=player_id, params=[('rarity_id', target_rarity_id)])
|
|
await db_patch('players', object_id=player_id, params=[('cost', target_cost)])
|
|
print(f" Rarity set to: Starter (ID 3)")
|
|
print(f" Cost set to: {target_cost}")
|
|
|
|
# Step 7: Skip image generation for now (user wants to review first)
|
|
print(f"\n✓ Skipping card image generation and S3 upload (will do after review)...")
|
|
api_image_url = f"https://pd.manticorum.com/api/v2/players/{player_id}/battingcard?d={release_date}"
|
|
s3_url = f"https://{AWS_BUCKET_NAME}.s3.{AWS_REGION}.amazonaws.com/cards/cardset-{cardset['id']:03d}/player-{player_id}/battingcard.png?d={release_date}"
|
|
print(f" Card preview URL: {api_image_url}")
|
|
print(f" Future S3 URL: {s3_url}")
|
|
|
|
print("\n" + "="*70)
|
|
print("✅ SUCCESS!")
|
|
print("="*70)
|
|
print(f"\nKalin Young created successfully!")
|
|
print(f" Player ID: {player_id}")
|
|
print(f" BattingCard ID: {battingcard_id}")
|
|
print(f" Positions: RF (Range 3, Error 7, Arm 0), LF (Range 4, Error 7, Arm 0)")
|
|
print(f" Bunting: C")
|
|
print(f" Running: {baserunning['running']}")
|
|
print(f" Stealing: {baserunning['steal_low']}-{baserunning['steal_high']} ({baserunning['steal_jump']:.5f})")
|
|
print(f" Pull Rate: ~25%")
|
|
print(f" Rarity: Starter")
|
|
print(f" Cost: {target_cost}")
|
|
print(f" Total OPS: {total_ops:.3f}")
|
|
print(f"\n Card Preview URL: {api_image_url}")
|
|
print(f" (Image not yet uploaded to S3 - awaiting review)")
|
|
print("\n" + "="*70)
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(create_kalin_young())
|