sim16/games.py

1016 lines
41 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json, random, os, math, jsonpickle, weather, archetypes
import database as db
from league_storage import get_mods, get_team_mods
from gametext import base_string, appearance_outcomes, game_strings_base
data_dir = "data"
games_config_file = os.path.join(data_dir, "games_config.json")
def config():
if not os.path.exists(os.path.dirname(games_config_file)):
os.makedirs(os.path.dirname(games_config_file))
if not os.path.exists(games_config_file):
#generate default config
config_dic = {
"default_length" : 3,
"stlat_weights" : {
"batting_stars" : 1, #batting
"pitching_stars" : 0.8, #pitching
"baserunning_stars" : 1, #baserunning
"defense_stars" : 1 #defense
},
"stolen_base_chance_mod" : 1,
"stolen_base_success_mod" : 1
}
with open(games_config_file, "w") as config_file:
json.dump(config_dic, config_file, indent=4)
return config_dic
else:
with open(games_config_file) as config_file:
return json.load(config_file)
class player(object):
def __init__(self, json_string):
self.stlats = json.loads(json_string)
self.id = self.stlats["id"]
self.name = self.stlats["name"]
self.game_stats = {
"outs_pitched" : 0,
"walks_allowed" : 0,
"hits_allowed" : 0,
"strikeouts_given" : 0,
"runs_allowed" : 0,
"plate_appearances" : 0,
"walks_taken" : 0,
"sacrifices" : 0,
"hits" : 0,
"home_runs" : 0,
"total_bases" : 0,
"rbis" : 0,
"strikeouts_taken" : 0
}
self.stat_name = self.name
if self.name == "Tim Locastro":
self.randomize_stars()
def star_string(self, key):
str_out = ""
starstring = str(self.stlats[key])
if ".5" in starstring:
starnum = int(starstring[0])
addhalf = True
else:
starnum = int(starstring[0])
addhalf = False
str_out += "" * starnum
if addhalf:
str_out += ""
return str_out
def __str__(self):
return self.name
def randomize_stars(self):
for key in ["batting_stars", "pitching_stars", "baserunning_stars", "defense_stars"]:
#random star value between 0 and 6.5
stars = random.randint(0,6)
half_star = random.random() < 0.5 #half star addition
if half_star:
stars = half_star + 0.5
self.stlats[key] = stars
def apply_mods(self, mod_dic):
for stat in iter(mod_dic.keys()):
self.stlats[stat] = self.stlats[stat] + mod_dic[stat]
class team(object):
def __init__(self):
self.name = None
self.lineup = []
self.lineup_position = 0
self.rotation = []
self.archetypes = {}
self.pitcher = None
self.score = 0
self.slogan = None
def find_player(self, name):
for index in range(0,len(self.lineup)):
if self.lineup[index].name.replace(" ", " ") == name:
return (self.lineup[index], index, self.lineup)
for index in range(0,len(self.rotation)):
if self.rotation[index].name.replace(" ", " ") == name:
return (self.rotation[index], index, self.rotation)
else:
return (None, None, None)
def find_player_spec(self, name, roster):
for s_index in range(0,len(roster)):
if roster[s_index].name.replace(" ", " ") == name:
return (roster[s_index], s_index)
def average_stars(self):
total_stars = 0
for _player in self.lineup:
total_stars += _player.stlats["batting_stars"]
for _player in self.rotation:
total_stars += _player.stlats["pitching_stars"]
return total_stars/(len(self.lineup) + len(self.rotation))
def swap_player(self, name):
this_player, index, roster = self.find_player(name)
if this_player is not None and len(roster) > 1:
if roster == self.lineup:
if self.add_pitcher(this_player):
roster.pop(index)
return True
else:
if self.add_lineup(this_player)[0]:
self.rotation.pop(index)
return True
return False
def delete_player(self, name):
this_player, index, roster = self.find_player(name)
if this_player is not None and len(roster) > 1:
roster.pop(index)
return True
else:
return False
def slide_player(self, name, new_spot):
this_player, index, roster = self.find_player(name)
if this_player is not None and new_spot <= len(roster):
roster.pop(index)
roster.insert(new_spot-1, this_player)
return True
else:
return False
def slide_player_spec(self, this_player_name, new_spot, roster):
index = None
for s_index in range(0,len(roster)):
if roster[s_index].name == this_player_name:
index = s_index
this_player = roster[s_index]
if index is None:
return False
elif new_spot <= len(roster):
roster.pop(index)
roster.insert(new_spot-1, this_player)
return True
else:
return False
def add_lineup(self, new_player):
if len(self.lineup) < 20:
self.lineup.append(new_player)
return (True,)
else:
return (False, "20 players in the lineup, maximum. We're being really generous here.")
def add_pitcher(self, new_player):
if len(self.rotation) < 8:
self.rotation.append(new_player)
return True
else:
return False
def set_pitcher(self, rotation_slot = None, use_lineup = False):
temp_rotation = self.rotation.copy()
if use_lineup:
for batter in self.lineup:
temp_rotation.append(batter)
if rotation_slot is None:
self.pitcher = random.choice(temp_rotation)
else:
self.pitcher = temp_rotation[(rotation_slot-1) % len(temp_rotation)]
def is_ready(self):
try:
return (len(self.lineup) >= 1 and len(self.rotation) > 0)
except AttributeError:
self.rotation = [self.pitcher]
self.pitcher = None
return (len(self.lineup) >= 1 and len(self.rotation) > 0)
def apply_team_mods(self, league_name):
mod_dic = get_team_mods(league_name, self.name)
if mod_dic != {} and mod_dic != None:
for player_name in iter(mod_dic.keys()):
this_player = self.find_player(player_name)[0]
if this_player is not None:
this_player.apply_mods(mod_dic[player_name])
def prepare_for_save(self):
self.lineup_position = 0
self.score = 0
if self.pitcher is not None and self.pitcher not in self.rotation:
self.rotation.append(self.pitcher)
self.pitcher = None
for this_player in self.lineup:
for stat in this_player.game_stats.keys():
this_player.game_stats[stat] = 0
for this_player in self.rotation:
for stat in this_player.game_stats.keys():
this_player.game_stats[stat] = 0
return self
def finalize(self):
if self.is_ready():
if self.pitcher == None:
self.set_pitcher()
while len(self.lineup) <= 4:
self.lineup.append(random.choice(self.lineup))
return self
else:
return False
class game(object):
def __init__(self, team1, team2, length=None):
self.over = False
self.random_weather_flag = False
self.teams = {"away" : team1, "home" : team2}
self.offense_archetypes = {}
self.defense_archetypes = {}
self.inning = 1
self.outs = 0
self.top_of_inning = True
self.last_update = ({},0) #this is a ({outcome}, runs) tuple
self.play_has_begun = False
self.owner = None
self.victory_lap = False
if length is not None:
self.max_innings = length
else:
self.max_innings = config()["default_length"]
self.bases = {1 : None, 2 : None, 3 : None}
self.weather = weather.Weather(self)
self.voice = None
self.current_batter = None
try:
self.archetypes = {team1.name : team1.archetypes, team2.name : team2.archetypes}
for this_team in [team1, team2]:
for this_player in this_team.lineup + this_team.rotation:
if this_player.name in this_team.archetypes.keys():
this_team.archetypes[this_player.name].modify_player_stats(this_player)
except:
pass
def occupied_bases(self):
occ_dic = {}
for base in self.bases.keys():
if self.bases[base] is not None:
occ_dic[base] = self.bases[base]
return occ_dic
def choose_next_batter(self):
if self.top_of_inning:
bat_team = self.teams["away"]
else:
bat_team = self.teams["home"]
self.current_batter = bat_team.lineup[bat_team.lineup_position % len(bat_team.lineup)]
self.weather.on_choose_next_batter(self)
def get_batter(self):
if self.current_batter == None:
self.choose_next_batter()
return self.current_batter
def get_pitcher(self):
if self.top_of_inning:
return self.teams["home"].pitcher
else:
return self.teams["away"].pitcher
def at_bat(self):
outcome = {}
pitcher = self.get_pitcher()
batter = self.get_batter()
if self.top_of_inning:
defender_list = self.teams["home"].lineup.copy()
else:
defender_list = self.teams["away"].lineup.copy()
defender_list.append(pitcher)
defender = random.choice(defender_list) #make pitchers field
outcome["batter"] = batter
outcome["pitcher"] = pitcher
outcome["defender"] = ""
if pitcher.name in self.defense_archetypes.keys():
outcome["pitcher_archetype"] = self.defense_archetypes[pitcher.name]
else:
outcome["pitcher_archetype"] = archetypes.Archetype
if batter.name in self.offense_archetypes.keys():
outcome["batter_archetype"] = self.offense_archetypes[batter.name]
else:
outcome["batter_archetype"] = archetypes.Archetype
if defender.name in self.defense_archetypes.keys():
outcome["defender_archetype"] = self.defense_archetypes[defender.name]
else:
outcome["defender_archetype"] = archetypes.Archetype
player_rolls = {}
player_rolls["bat_stat"] = random_star_gen("batting_stars", batter)
player_rolls["pitch_stat"] = random_star_gen("pitching_stars", pitcher)
self.weather.modify_atbat_stats(player_rolls)
roll = {}
roll["pb_system_stat"] = (random.gauss(1*math.erf((player_rolls["bat_stat"] - player_rolls["pitch_stat"])*1.5)-1.8,2.2))
roll["hitnum"] = random.gauss(2*math.erf(player_rolls["bat_stat"]/4)-1,3)
self.weather.modify_atbat_roll(outcome, roll, defender)
outcome["batter_archetype"].modify_bat_rolls(outcome, roll)
outcome["pitcher_archetype"].modify_bat_rolls(outcome, roll)
if roll["pb_system_stat"] <= 0:
outcome["ishit"] = False
fc_flag = False
if roll["hitnum"] < -1.5:
outcome["outcome"] = random.choice([appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging])
elif roll["hitnum"] < 1:
outcome["outcome"] = appearance_outcomes.groundout
outcome["defender"] = defender
elif roll["hitnum"] < 4:
outcome["outcome"] = appearance_outcomes.flyout
outcome["defender"] = defender
else:
outcome["outcome"] = appearance_outcomes.walk
outcome["batter_archetype"].modify_out_type(outcome)
outcome["pitcher_archetype"].modify_out_type(outcome)
if self.bases[1] is not None and roll["hitnum"] < -2 and (self.outs != 2 or self.weather.out_extension):
outcome["outcome"] = appearance_outcomes.doubleplay
outcome["defender"] = ""
#for base in self.bases.values():
#if base is not None:
#fc_flag = True
runners = [(0,self.get_batter())]
for base in range(1,4):
if self.bases[base] == None:
break
runners.append((base, self.bases[base]))
outcome["runners"] = runners #list of consecutive baserunners: (base number, player object)
if self.outs < 2 and len(runners) > 1: #fielder's choice replaces not great groundouts if any forceouts are present
def_stat = random_star_gen("defense_stars", defender)
if -1.5 <= roll["hitnum"] and roll["hitnum"] < -0.5: #poorly hit groundouts
outcome["outcome"] = appearance_outcomes.fielderschoice
outcome["defender"] = ""
if outcome["outcome"] not in [appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging] and 2.5 <= roll["hitnum"] and self.outs < 2: #well hit flyouts can lead to sacrifice flies/advanced runners
if self.bases[2] is not None or self.bases[3] is not None:
outcome["advance"] = True
else:
outcome["ishit"] = True
if roll["hitnum"] < 1:
outcome["outcome"] = appearance_outcomes.single
elif roll["hitnum"] < 2.85 or "error" in outcome.keys():
outcome["outcome"] = appearance_outcomes.double
elif roll["hitnum"] < 3.1:
outcome["outcome"] = appearance_outcomes.triple
else:
if self.bases[1] is not None and self.bases[2] is not None and self.bases[3] is not None:
outcome["outcome"] = appearance_outcomes.grandslam
else:
outcome["outcome"] = appearance_outcomes.homerun
outcome["batter_archetype"].modify_hit_type(outcome)
outcome["pitcher_archetype"].modify_hit_type(outcome)
return outcome
def thievery_attempts(self): #returns either false or "at-bat" outcome
thieves = []
attempts = []
outcome = {}
for base in self.bases.keys():
if self.bases[base] is not None and base != 3: #no stealing home in simsim, sorry stu
if self.bases[base+1] is None: #if there's somewhere to go
thieves.append((self.bases[base], base))
for baserunner, start_base in thieves:
stats = {
"run_stars": random_star_gen("baserunning_stars", baserunner)*config()["stolen_base_chance_mod"],
"def_stars": random_star_gen("defense_stars", self.get_pitcher())
}
self.weather.modify_steal_stats(stats)
if self.get_pitcher().name in self.defense_archetypes.keys():
outcome["pitcher_archetype"] = self.defense_archetypes[self.get_pitcher().name]
else:
outcome["pitcher_archetype"] = archetypes.Archetype
if baserunner.name in self.offense_archetypes.keys():
outcome["baserunner_archetype"] = self.offense_archetypes[baserunner.name]
else:
outcome["baserunner_archetype"] = archetypes.Archetype
outcome["pitcher_archetype"].hold_runner(outcome, stats)
if stats["run_stars"] >= (stats["def_stars"] - 1.5): #if baserunner isn't worse than pitcher
roll = random.random()
outcome["baserunner_archetype"].steal_check(outcome, roll)
if roll >= (-(((stats["run_stars"]+1)/14)**2)+1): #plug it into desmos or something, you'll see
attempts.append((baserunner, start_base))
if len(attempts) == 0:
return False
else:
return (self.steals_check(attempts, outcome), 0) #effectively an at-bat outcome with no score
def steals_check(self, attempts, outcome):
if self.top_of_inning:
defense_team = self.teams["home"]
else:
defense_team = self.teams["away"]
for baserunner, start_base in attempts:
defender = random.choice(defense_team.lineup) #excludes pitcher
run_stat = random_star_gen("baserunning_stars", baserunner)
def_stat = random_star_gen("defense_stars", defender)
run_roll = random.gauss(2*math.erf((run_stat-def_stat)/4)-1,3)*config()["stolen_base_success_mod"]
outcome["baserunner_archetype"].modify_steal_attempt(outcome, run_roll)
outcome["pitcher_archetype"].modify_steal_attempt(outcome, run_roll)
if defender.name in self.defense_archetypes.keys():
self.defense_archetypes[defender.name].modify_steal_attempt(outcome, run_roll)
if start_base == 2:
run_roll = run_roll * .9 #stealing third is harder
if run_roll < 1:
successful = False
self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1
else:
successful = True
self.bases[start_base+1] = baserunner
self.bases[start_base] = None
self.voice.stealing(outcome, baserunner.name, base_string(start_base+1), defender.name, successful)
self.weather.steal_post_activate(self, outcome)
if self.outs >= 3:
self.flip_inning()
return outcome
def baserunner_check(self, defender, outcome):
def_stat = random_star_gen("defense_stars", defender)
if outcome["outcome"] == appearance_outcomes.homerun or outcome["outcome"] == appearance_outcomes.grandslam:
runs = 1
for base in self.bases.values():
if base is not None:
runs += 1
self.bases = {1 : None, 2 : None, 3 : None}
if "veil" in outcome.keys():
if runs < 4:
self.bases[runs] = self.get_batter()
else:
runs += 1
return runs
elif "advance" in outcome.keys():
runs = 0
if self.bases[3] is not None:
outcome["outcome"] = appearance_outcomes.sacrifice
self.get_batter().game_stats["sacrifices"] += 1
self.bases[3] = None
runs = 1
if self.bases[2] is not None:
run_roll = random.gauss(2*math.erf((random_star_gen("baserunning_stars", self.bases[2])-def_stat)/4)-1,3)
if self.bases[2].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[2].name].modify_tag_up_roll(outcome, run_roll)
outcome["defender_archetype"].modify_tag_up_roll(outcome, run_roll)
if run_roll > 2:
self.bases[3] = self.bases[2]
self.bases[2] = None
return runs
elif outcome["outcome"] == appearance_outcomes.fielderschoice:
furthest_base, runner = outcome["runners"].pop() #get furthest baserunner
self.bases[furthest_base] = None
outcome["fc_out"] = (runner.name, base_string(furthest_base+1)) #runner thrown out
outcome["runner"] = runner.name
outcome["base"] = furthest_base+1
for index in range(0,len(outcome["runners"])):
base, this_runner = outcome["runners"].pop()
self.bases[base+1] = this_runner #includes batter, at base 0
if self.bases[3] is not None and furthest_base == 1: #fielders' choice with runners on the corners
self.bases[3] = None
return 1
return 0
elif outcome["outcome"] == appearance_outcomes.groundout or outcome["outcome"] == appearance_outcomes.doubleplay:
runs = 0
if self.bases[3] is not None:
runs += 1
self.bases[3] = None
if self.bases[2] is not None:
run_roll = random.gauss(2*math.erf((random_star_gen("baserunning_stars", self.bases[2])-def_stat)/4)-1,3)
if self.bases[2].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[2].name].modify_advance_roll(outcome, run_roll)
outcome["defender_archetype"].modify_advance_roll(outcome, run_roll)
if run_roll > 1.5 or outcome["outcome"] == appearance_outcomes.doubleplay: #double play gives them time to run, guaranteed
self.bases[3] = self.bases[2]
self.bases[2] = None
if self.bases[1] is not None: #double plays set this to None before this call
run_roll = random.gauss(2*math.erf((random_star_gen("baserunning_stars", self.bases[1])-def_stat)/4)-1,3)
if self.bases[1].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[1].name].modify_advance_roll(outcome, run_roll)
outcome["defender_archetype"].modify_advance_roll(outcome, run_roll)
if run_roll < 2 or self.bases[2] is not None: #if runner can't make it or if baserunner blocking on second, convert to fielder's choice
outcome["outcome"] == appearance_outcomes.fielderschoice
runners = [(0,self.get_batter())]
for base in range(1,4):
if self.bases[base] == None:
break
runners.append((base, self.bases[base]))
outcome["runners"] = runners #rebuild consecutive runners
return runs + self.baserunner_check(defender, outcome) #run again as fielder's choice instead
else:
self.bases[2] = self.bases[1]
self.bases[1] = None
return runs
elif outcome["ishit"]:
runs = 0
if outcome["outcome"] == appearance_outcomes.single:
if self.bases[3] is not None:
runs += 1
self.bases[3] = None
if self.bases[2] is not None:
run_roll = random.gauss(math.erf(random_star_gen("baserunning_stars", self.bases[2])-def_stat)-.5,1.5)
if self.bases[2].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[2].name].modify_extra_running_roll(outcome, run_roll)
outcome["defender_archetype"].modify_extra_running_roll(outcome, run_roll)
if run_roll > 0:
runs += 1
else:
self.bases[3] = self.bases[2]
self.bases[2] = None
if self.bases[1] is not None:
if self.bases[3] is None:
run_roll = random.gauss(math.erf(random_star_gen("baserunning_stars", self.bases[1])-def_stat)-.5,1.5)
if self.bases[1].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[1].name].modify_extra_running_roll(outcome, run_roll)
outcome["defender_archetype"].modify_extra_running_roll(outcome, run_roll)
if run_roll > 0.75:
self.bases[3] = self.bases[1]
else:
self.bases[2] = self.bases[1]
else:
self.bases[2] = self.bases[1]
self.bases[1] = None
self.bases[1] = self.get_batter()
return runs
elif outcome["outcome"] == appearance_outcomes.double:
runs = 0
if self.bases[3] is not None:
runs += 1
self.bases[3] = None
if self.bases[2] is not None:
runs += 1
self.bases[2] = None
if self.bases[1] is not None:
run_roll = random.gauss(math.erf(random_star_gen("baserunning_stars", self.bases[1])-def_stat)-.5,1.5)
if self.bases[1].name in self.offense_archetypes.keys():
self.offense_archetypes[self.bases[1].name].modify_extra_running_roll(outcome, run_roll)
outcome["defender_archetype"].modify_extra_running_roll(outcome, run_roll)
if run_roll > 1:
runs += 1
self.bases[1] = None
else:
self.bases[3] = self.bases[1]
self.bases[1] = None
self.bases[2] = self.get_batter()
return runs
elif outcome["outcome"] == appearance_outcomes.triple:
runs = 0
for basenum in self.bases.keys():
if self.bases[basenum] is not None:
runs += 1
self.bases[basenum] = None
self.bases[3] = self.get_batter()
return runs
def batterup(self):
scores_to_add = 0
if "twopart" not in self.last_update[0]:
result = self.at_bat()
if self.top_of_inning:
offense_team = self.teams["away"]
defense_team = self.teams["home"]
else:
offense_team = self.teams["home"]
defense_team = self.teams["away"]
self.offense_archetypes = self.archetypes[offense_team.name]
self.defense_archetypes = self.archetypes[defense_team.name]
defenders = defense_team.lineup.copy()
defenders.append(defense_team.pitcher)
defender = random.choice(defenders) #pitcher can field outs now :3
result["defender"] = defender
result["defense_team"] = defense_team
result["offense_team"] = offense_team
if "advance" in result.keys() and self.bases[3] is not None:
result["outcome"] = appearance_outcomes.sacrifice
result["runner"] = self.bases[3].name
text_list = getattr(self.voice, result["outcome"].name)
voice_index = random.randrange(0, len(text_list))
result["voiceindex"] = voice_index
else:
result = {}
result = self.voice.activate(self.last_update[0], result, self)
if "twopart" not in result:
self.weather.activate(self, result) # possibly modify result in-place
if "text_only" in result:
return (result, 0)
if "twopart" in result:
if self.voice.post_format != []:
format_list = []
for extra_format in self.voice.post_format:
try:
if extra_format == "base":
format_list.append(base_string(result["base"]))
elif extra_format == "runner":
format_list.append(result["runner"])
except KeyError:
format_list.append("None")
self.voice.post_format = []
result["displaytext"] = result["displaytext"].format(*format_list)
return (result, 0)
if result["ishit"]: #if batter gets a hit:
self.get_batter().game_stats["hits"] += 1
self.get_pitcher().game_stats["hits_allowed"] += 1
if result["outcome"] == appearance_outcomes.single:
self.get_batter().game_stats["total_bases"] += 1
elif result["outcome"] == appearance_outcomes.double:
self.get_batter().game_stats["total_bases"] += 2
elif result["outcome"] == appearance_outcomes.triple:
self.get_batter().game_stats["total_bases"] += 3
elif result["outcome"] == appearance_outcomes.homerun or result["outcome"] == appearance_outcomes.grandslam:
self.get_batter().game_stats["total_bases"] += 4
self.get_batter().game_stats["home_runs"] += 1
scores_to_add += self.baserunner_check(result["defender"], result)
else: #batter did not get a hit
if result["outcome"] == appearance_outcomes.walk:
walkers = [(0,self.get_batter())]
for base in range(1,4):
if self.bases[base] == None:
break
walkers.append((base, self.bases[base]))
for i in range(0, len(walkers)):
this_walker = walkers.pop()
if this_walker[0] == 3:
self.bases[3] = None
scores_to_add += 1
else:
self.bases[this_walker[0]+1] = this_walker[1] #this moves all consecutive baserunners one forward
self.get_batter().game_stats["walks_taken"] += 1
self.get_pitcher().game_stats["walks_allowed"] += 1
elif result["outcome"] == appearance_outcomes.doubleplay:
self.get_pitcher().game_stats["outs_pitched"] += 2
self.outs += 2
self.bases[1] = None
if self.outs < 3:
scores_to_add += self.baserunner_check(result["defender"], result)
self.get_batter().game_stats["rbis"] -= scores_to_add #remove the fake rbi from the player in advance
elif result["outcome"] == appearance_outcomes.fielderschoice or result["outcome"] == appearance_outcomes.groundout:
self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1
if self.outs < 3:
scores_to_add += self.baserunner_check(result["defender"], result)
elif "advance" in result.keys() or result["outcome"] == appearance_outcomes.sacrifice:
self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1
if self.outs < 3:
if self.bases[3] is not None:
result["runner"] = self.bases[3].name
self.get_batter().game_stats["sacrifices"] += 1
scores_to_add += self.baserunner_check(result["defender"], result)
elif result["outcome"] == appearance_outcomes.strikeoutlooking or result["outcome"] == appearance_outcomes.strikeoutswinging:
self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1
self.get_batter().game_stats["strikeouts_taken"] += 1
self.get_pitcher().game_stats["strikeouts_given"] += 1
else:
self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1
self.get_batter().game_stats["plate_appearances"] += 1
if self.voice.post_format != []:
format_list = []
for extra_format in self.voice.post_format:
try:
if extra_format == "base":
format_list.append(base_string(result["base"]))
elif extra_format == "runner":
format_list.append(result["runner"])
except KeyError:
format_list.append("None")
self.voice.post_format = []
result["displaytext"] = result["displaytext"].format(*format_list)
if self.outs < 3:
result["offense_team"].score += scores_to_add #only add points if inning isn't over
else:
scores_to_add = 0
self.get_batter().game_stats["rbis"] += scores_to_add
self.get_pitcher().game_stats["runs_allowed"] += scores_to_add
result["offense_team"].lineup_position += 1 #put next batter up
self.choose_next_batter()
self.weather.post_activate(self, result)
if self.outs >= 3:
self.flip_inning()
return (result, scores_to_add) #returns ab information and scores
def flip_inning(self):
for base in self.bases.keys():
self.bases[base] = None
self.outs = 0
self.top_of_inning = not self.top_of_inning
if self.random_weather_flag and self.top_of_inning:
setattr(self, "weather", random.choice(list(weather.safe_weathers().values()))(self))
self.weather.on_flip_inning(self)
self.choose_next_batter()
if self.top_of_inning:
self.inning += 1
if self.inning > self.max_innings and self.teams["home"].score != self.teams["away"].score: #game over
self.over = True
try: #if something goes wrong with OBL don't erase game
if self.max_innings >= 9 or self.weather.name in ["Leaf Eddies", "Torrential Downpour"]:
this_xvi_team = None
db.save_obl_results(self.teams["home"] if self.teams["home"].score > self.teams["away"].score else self.teams["away"], self.teams["home"] if self.teams["home"].score < self.teams["away"].score else self.teams["away"], xvi_team=this_xvi_team)
except:
pass
def end_of_game_report(self):
return {
"away_team" : self.teams["away"],
"away_pitcher" : self.teams["away"].pitcher,
"home_team" : self.teams["home"],
"home_pitcher" : self.teams["home"].pitcher
}
def named_bases(self):
name_bases = {}
for base in range(1,4):
if self.bases[base] is not None:
name_bases[base] = self.bases[base].name
else:
name_bases[base] = None
return name_bases
def gamestate_update_full(self):
self.play_has_begun = True
attempts = self.thievery_attempts()
if attempts == False or "twopart" in self.last_update[0]:
self.last_update = self.batterup()
else:
self.last_update = attempts
return self.gamestate_display_full()
def gamestate_display_full(self):
if not self.over:
return "Still in progress."
else:
return f"""Game over! Final score: **{self.teams['away'].score} - {self.teams['home'].score}**"""
def add_stats(self):
players = self.get_stats()
db.add_stats(players)
def get_stats(self):
players = []
for this_player in self.teams["away"].lineup:
players.append((this_player.stat_name, this_player.game_stats))
for this_player in self.teams["home"].lineup:
players.append((this_player.stat_name, this_player.game_stats))
players.append((self.teams["home"].pitcher.stat_name, self.teams["home"].pitcher.game_stats))
players.append((self.teams["away"].pitcher.stat_name, self.teams["away"].pitcher.game_stats))
return players
def get_team_specific_stats(self):
players = {
self.teams["away"].name : [],
self.teams["home"].name : []
}
for this_player in self.teams["away"].lineup:
try:
players[self.teams["away"].name].append((this_player.stat_name, this_player.game_stats))
except AttributeError:
players[self.teams["away"].name].append((this_player.name, this_player.game_stats))
for this_player in self.teams["home"].lineup:
try:
players[self.teams["home"].name].append((this_player.stat_name, this_player.game_stats))
except AttributeError:
players[self.teams["home"].name].append((this_player.name, this_player.game_stats))
try:
players[self.teams["home"].name].append((self.teams["home"].pitcher.stat_name, self.teams["home"].pitcher.game_stats))
except AttributeError:
players[self.teams["home"].name].append((self.teams["home"].pitcher.name, self.teams["home"].pitcher.game_stats))
try:
players[self.teams["away"].name].append((self.teams["away"].pitcher.stat_name, self.teams["away"].pitcher.game_stats))
except AttributeError:
players[self.teams["away"].name].append((self.teams["away"].pitcher.name, self.teams["away"].pitcher.game_stats))
return players
def random_star_gen(key, player):
return random.gauss(config()["stlat_weights"][key] * player.stlats[key],1)
# innings_pitched
# walks_allowed
# strikeouts_given
# runs_allowed
# plate_appearances
# walks
# hits
# total_bases
# rbis
# walks_taken
# strikeouts_taken
def get_team(name):
try:
team_json = jsonpickle.decode(db.get_team(name)[0], keys=True, classes=team)
if team_json is not None:
if team_json.pitcher is not None: #detects old-format teams, adds pitcher
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
if not hasattr(team_json, "archetypes"):
team_json.archetypes = {}
return team_json
return None
except AttributeError:
team_json.rotation = []
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
return team_json
except:
return None
def get_team_and_owner(name):
try:
counter, name, team_json_string, timestamp, owner_id = db.get_team(name, owner=True)
team_json = jsonpickle.decode(team_json_string, keys=True, classes=team)
if team_json is not None:
if team_json.pitcher is not None: #detects old-format teams, adds pitcher
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
if not hasattr(team_json, "archetypes"):
team_json.archetypes = {}
return (team_json, owner_id)
return (None, None)
except AttributeError:
team_json.rotation = []
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
return (team_json, owner_id)
except:
return (None, None)
def save_team(this_team, user_id):
try:
this_team.prepare_for_save()
team_json_string = jsonpickle.encode(this_team, keys=True)
db.save_team(this_team.name, team_json_string, user_id)
return True
except:
return None
def update_team(this_team):
try:
this_team.prepare_for_save()
team_json_string = jsonpickle.encode(this_team, keys=True)
db.update_team(this_team.name, team_json_string)
return True
except:
return None
def get_all_teams():
teams = []
for team_pickle in db.get_all_teams():
this_team = jsonpickle.decode(team_pickle[0], keys=True, classes=team)
teams.append(this_team)
return teams
def search_team(search_term):
teams = []
for team_pickle in db.search_teams(search_term):
team_json = jsonpickle.decode(team_pickle[0], keys=True, classes=team)
try:
if team_json.pitcher is not None:
if len(team_json.rotation) == 0: #detects old-format teams, adds pitcher
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
if not hasattr(team_json, "archetypes"):
team_json.archetypes = {}
except AttributeError:
team_json.rotation = []
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
except:
return None
teams.append(team_json)
return teams
def get_filtered_teams(teams_to_remove):
teams = []
for team_pickle in db.get_all_teams():
this_team = jsonpickle.decode(team_pickle[0], keys=True, classes=team)
if this_team.name not in teams_to_remove:
teams.append(this_team)
return teams