Merge pull request #236 from Sakimori/rebuild

Rebuild
This commit is contained in:
Sakimori 2021-03-31 18:45:06 -04:00 committed by GitHub
commit d1ae30e850
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1124 additions and 535 deletions

View file

@ -457,6 +457,15 @@ def set_obl_rival(base_team, rival):
conn.commit() conn.commit()
conn.close() conn.close()
def clear_obl():
conn = create_connection()
if conn is not None:
c=conn.cursor()
c.execute("DELETE FROM one_big_league")
conn.commit()
conn.close()
def list_to_newline_string(list): def list_to_newline_string(list):
string = "" string = ""
for element in list: for element in list:

146
games.py
View file

@ -1,7 +1,6 @@
import json, random, os, math, jsonpickle import json, random, os, math, jsonpickle, weather
import database as db import database as db
import weather from gametext import base_string, appearance_outcomes, game_strings_base
from gametext import base_string, appearance_outcomes
data_dir = "data" data_dir = "data"
games_config_file = os.path.join(data_dir, "games_config.json") games_config_file = os.path.join(data_dir, "games_config.json")
@ -82,17 +81,17 @@ class team(object):
def find_player(self, name): def find_player(self, name):
for index in range(0,len(self.lineup)): for index in range(0,len(self.lineup)):
if self.lineup[index].name == name: if self.lineup[index].name.replace(" ", " ") == name:
return (self.lineup[index], index, self.lineup) return (self.lineup[index], index, self.lineup)
for index in range(0,len(self.rotation)): for index in range(0,len(self.rotation)):
if self.rotation[index].name == name: if self.rotation[index].name.replace(" ", " ") == name:
return (self.rotation[index], index, self.rotation) return (self.rotation[index], index, self.rotation)
else: else:
return (None, None, None) return (None, None, None)
def find_player_spec(self, name, roster): def find_player_spec(self, name, roster):
for s_index in range(0,len(roster)): for s_index in range(0,len(roster)):
if roster[s_index].name == name: if roster[s_index].name.replace(" ", " ") == name:
return (roster[s_index], s_index) return (roster[s_index], s_index)
def average_stars(self): def average_stars(self):
@ -223,6 +222,7 @@ class game(object):
self.max_innings = config()["default_length"] self.max_innings = config()["default_length"]
self.bases = {1 : None, 2 : None, 3 : None} self.bases = {1 : None, 2 : None, 3 : None}
self.weather = weather.Weather(self) self.weather = weather.Weather(self)
self.voice = None
self.current_batter = None self.current_batter = None
def occupied_bases(self): def occupied_bases(self):
@ -266,6 +266,7 @@ class game(object):
defender = random.choice(defender_list) #make pitchers field defender = random.choice(defender_list) #make pitchers field
outcome["batter"] = batter outcome["batter"] = batter
outcome["pitcher"] = pitcher
outcome["defender"] = "" outcome["defender"] = ""
player_rolls = {} player_rolls = {}
@ -285,18 +286,18 @@ class game(object):
outcome["ishit"] = False outcome["ishit"] = False
fc_flag = False fc_flag = False
if roll["hitnum"] < -1.5: if roll["hitnum"] < -1.5:
outcome["text"] = random.choice([appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging]) outcome["outcome"] = random.choice([appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging])
elif roll["hitnum"] < 1: elif roll["hitnum"] < 1:
outcome["text"] = appearance_outcomes.groundout outcome["outcome"] = appearance_outcomes.groundout
outcome["defender"] = defender outcome["defender"] = defender
elif roll["hitnum"] < 4: elif roll["hitnum"] < 4:
outcome["text"] = appearance_outcomes.flyout outcome["outcome"] = appearance_outcomes.flyout
outcome["defender"] = defender outcome["defender"] = defender
else: else:
outcome["text"] = appearance_outcomes.walk outcome["outcome"] = appearance_outcomes.walk
if self.bases[1] is not None and roll["hitnum"] < -2 and self.outs != 2: if self.bases[1] is not None and roll["hitnum"] < -2 and self.outs != 2:
outcome["text"] = appearance_outcomes.doubleplay outcome["outcome"] = appearance_outcomes.doubleplay
outcome["defender"] = "" outcome["defender"] = ""
#for base in self.bases.values(): #for base in self.bases.values():
@ -313,7 +314,7 @@ class game(object):
if self.outs < 2 and len(runners) > 1: #fielder's choice replaces not great groundouts if any forceouts are present 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) def_stat = random_star_gen("defense_stars", defender)
if -1.5 <= roll["hitnum"] and roll["hitnum"] < -0.5: #poorly hit groundouts if -1.5 <= roll["hitnum"] and roll["hitnum"] < -0.5: #poorly hit groundouts
outcome["text"] = appearance_outcomes.fielderschoice outcome["outcome"] = appearance_outcomes.fielderschoice
outcome["defender"] = "" outcome["defender"] = ""
if 2.5 <= roll["hitnum"] and self.outs < 2: #well hit flyouts can lead to sacrifice flies/advanced runners if 2.5 <= roll["hitnum"] and self.outs < 2: #well hit flyouts can lead to sacrifice flies/advanced runners
@ -322,16 +323,16 @@ class game(object):
else: else:
outcome["ishit"] = True outcome["ishit"] = True
if roll["hitnum"] < 1: if roll["hitnum"] < 1:
outcome["text"] = appearance_outcomes.single outcome["outcome"] = appearance_outcomes.single
elif roll["hitnum"] < 2.85 or "error" in outcome.keys(): elif roll["hitnum"] < 2.85 or "error" in outcome.keys():
outcome["text"] = appearance_outcomes.double outcome["outcome"] = appearance_outcomes.double
elif roll["hitnum"] < 3.1: elif roll["hitnum"] < 3.1:
outcome["text"] = appearance_outcomes.triple outcome["outcome"] = appearance_outcomes.triple
else: else:
if self.bases[1] is not None and self.bases[2] is not None and self.bases[3] is not None: if self.bases[1] is not None and self.bases[2] is not None and self.bases[3] is not None:
outcome["text"] = appearance_outcomes.grandslam outcome["outcome"] = appearance_outcomes.grandslam
else: else:
outcome["text"] = appearance_outcomes.homerun outcome["outcome"] = appearance_outcomes.homerun
return outcome return outcome
def thievery_attempts(self): #returns either false or "at-bat" outcome def thievery_attempts(self): #returns either false or "at-bat" outcome
@ -366,7 +367,6 @@ class game(object):
defense_team = self.teams["away"] defense_team = self.teams["away"]
outcome = {} outcome = {}
outcome["steals"] = []
for baserunner, start_base in attempts: for baserunner, start_base in attempts:
defender = random.choice(defense_team.lineup) #excludes pitcher defender = random.choice(defense_team.lineup) #excludes pitcher
@ -376,14 +376,16 @@ class game(object):
if start_base == 2: if start_base == 2:
run_roll = run_roll * .9 #stealing third is harder run_roll = run_roll * .9 #stealing third is harder
if run_roll < 1: if run_roll < 1:
outcome["steals"].append(f"{baserunner} was caught stealing {base_string(start_base+1)} base by {defender}!") successful = False
self.get_pitcher().game_stats["outs_pitched"] += 1 self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1 self.outs += 1
else: else:
outcome["steals"].append(f"{baserunner} steals {base_string(start_base+1)} base!") successful = True
self.bases[start_base+1] = baserunner self.bases[start_base+1] = baserunner
self.bases[start_base] = None self.bases[start_base] = None
self.voice.stealing(outcome, baserunner.name, base_string(start_base+1), defender.name, successful)
if self.outs >= 3: if self.outs >= 3:
self.flip_inning() self.flip_inning()
@ -391,7 +393,7 @@ class game(object):
def baserunner_check(self, defender, outcome): def baserunner_check(self, defender, outcome):
def_stat = random_star_gen("defense_stars", defender) def_stat = random_star_gen("defense_stars", defender)
if outcome["text"] == appearance_outcomes.homerun or outcome["text"] == appearance_outcomes.grandslam: if outcome["outcome"] == appearance_outcomes.homerun or outcome["outcome"] == appearance_outcomes.grandslam:
runs = 1 runs = 1
for base in self.bases.values(): for base in self.bases.values():
if base is not None: if base is not None:
@ -407,7 +409,7 @@ class game(object):
elif "advance" in outcome.keys(): elif "advance" in outcome.keys():
runs = 0 runs = 0
if self.bases[3] is not None: if self.bases[3] is not None:
outcome["text"] = appearance_outcomes.sacrifice outcome["outcome"] = appearance_outcomes.sacrifice
self.get_batter().game_stats["sacrifices"] += 1 self.get_batter().game_stats["sacrifices"] += 1
self.bases[3] = None self.bases[3] = None
runs = 1 runs = 1
@ -418,10 +420,12 @@ class game(object):
self.bases[2] = None self.bases[2] = None
return runs return runs
elif outcome["text"] == appearance_outcomes.fielderschoice: elif outcome["outcome"] == appearance_outcomes.fielderschoice:
furthest_base, runner = outcome["runners"].pop() #get furthest baserunner furthest_base, runner = outcome["runners"].pop() #get furthest baserunner
self.bases[furthest_base] = None self.bases[furthest_base] = None
outcome["fc_out"] = (runner.name, base_string(furthest_base+1)) #runner thrown out 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"])): for index in range(0,len(outcome["runners"])):
base, this_runner = outcome["runners"].pop() base, this_runner = outcome["runners"].pop()
self.bases[base+1] = this_runner #includes batter, at base 0 self.bases[base+1] = this_runner #includes batter, at base 0
@ -430,20 +434,20 @@ class game(object):
return 1 return 1
return 0 return 0
elif outcome["text"] == appearance_outcomes.groundout or outcome["text"] == appearance_outcomes.doubleplay: elif outcome["outcome"] == appearance_outcomes.groundout or outcome["outcome"] == appearance_outcomes.doubleplay:
runs = 0 runs = 0
if self.bases[3] is not None: if self.bases[3] is not None:
runs += 1 runs += 1
self.bases[3] = None self.bases[3] = None
if self.bases[2] is not 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) run_roll = random.gauss(2*math.erf((random_star_gen("baserunning_stars", self.bases[2])-def_stat)/4)-1,3)
if run_roll > 1.5 or outcome["text"] == appearance_outcomes.doubleplay: #double play gives them time to run, guaranteed 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[3] = self.bases[2]
self.bases[2] = None self.bases[2] = None
if self.bases[1] is not None: #double plays set this to None before this call 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) run_roll = random.gauss(2*math.erf((random_star_gen("baserunning_stars", self.bases[1])-def_stat)/4)-1,3)
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 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["text"] == appearance_outcomes.fielderschoice outcome["outcome"] == appearance_outcomes.fielderschoice
runners = [(0,self.get_batter())] runners = [(0,self.get_batter())]
for base in range(1,4): for base in range(1,4):
if self.bases[base] == None: if self.bases[base] == None:
@ -458,7 +462,7 @@ class game(object):
elif outcome["ishit"]: elif outcome["ishit"]:
runs = 0 runs = 0
if outcome["text"] == appearance_outcomes.single: if outcome["outcome"] == appearance_outcomes.single:
if self.bases[3] is not None: if self.bases[3] is not None:
runs += 1 runs += 1
self.bases[3] = None self.bases[3] = None
@ -483,7 +487,7 @@ class game(object):
self.bases[1] = self.get_batter() self.bases[1] = self.get_batter()
return runs return runs
elif outcome["text"] == appearance_outcomes.double: elif outcome["outcome"] == appearance_outcomes.double:
runs = 0 runs = 0
if self.bases[3] is not None: if self.bases[3] is not None:
runs += 1 runs += 1
@ -503,7 +507,7 @@ class game(object):
return runs return runs
elif outcome["text"] == appearance_outcomes.triple: elif outcome["outcome"] == appearance_outcomes.triple:
runs = 0 runs = 0
for basenum in self.bases.keys(): for basenum in self.bases.keys():
if self.bases[basenum] is not None: if self.bases[basenum] is not None:
@ -515,13 +519,10 @@ class game(object):
def batterup(self): def batterup(self):
scores_to_add = 0 scores_to_add = 0
if "twopart" not in self.last_update[0]:
result = self.at_bat() result = self.at_bat()
self.weather.activate(self, result) # possibly modify result in-place
if "text_only" in result:
return (result, 0)
if self.top_of_inning: if self.top_of_inning:
offense_team = self.teams["away"] offense_team = self.teams["away"]
defense_team = self.teams["home"] defense_team = self.teams["home"]
@ -533,27 +534,60 @@ class game(object):
defenders = defense_team.lineup.copy() defenders = defense_team.lineup.copy()
defenders.append(defense_team.pitcher) defenders.append(defense_team.pitcher)
defender = random.choice(defenders) #pitcher can field outs now :3 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 = {}
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:
if extra_format == "base":
format_list.append(base_string(result["base"]))
elif extra_format == "runner":
format_list.append(result["runner"])
self.voice.post_format = []
result["displaytext"] = result["displaytext"].format(*format_list)
return (result, 0)
if result["ishit"]: #if batter gets a hit: if result["ishit"]: #if batter gets a hit:
self.get_batter().game_stats["hits"] += 1 self.get_batter().game_stats["hits"] += 1
self.get_pitcher().game_stats["hits_allowed"] += 1 self.get_pitcher().game_stats["hits_allowed"] += 1
if result["text"] == appearance_outcomes.single: if result["outcome"] == appearance_outcomes.single:
self.get_batter().game_stats["total_bases"] += 1 self.get_batter().game_stats["total_bases"] += 1
elif result["text"] == appearance_outcomes.double: elif result["outcome"] == appearance_outcomes.double:
self.get_batter().game_stats["total_bases"] += 2 self.get_batter().game_stats["total_bases"] += 2
elif result["text"] == appearance_outcomes.triple: elif result["outcome"] == appearance_outcomes.triple:
self.get_batter().game_stats["total_bases"] += 3 self.get_batter().game_stats["total_bases"] += 3
elif result["text"] == appearance_outcomes.homerun or result["text"] == appearance_outcomes.grandslam: 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["total_bases"] += 4
self.get_batter().game_stats["home_runs"] += 1 self.get_batter().game_stats["home_runs"] += 1
scores_to_add += self.baserunner_check(defender, result) scores_to_add += self.baserunner_check(result["defender"], result)
else: #batter did not get a hit else: #batter did not get a hit
if result["text"] == appearance_outcomes.walk: if result["outcome"] == appearance_outcomes.walk:
walkers = [(0,self.get_batter())] walkers = [(0,self.get_batter())]
for base in range(1,4): for base in range(1,4):
if self.bases[base] == None: if self.bases[base] == None:
@ -570,29 +604,30 @@ class game(object):
self.get_batter().game_stats["walks_taken"] += 1 self.get_batter().game_stats["walks_taken"] += 1
self.get_pitcher().game_stats["walks_allowed"] += 1 self.get_pitcher().game_stats["walks_allowed"] += 1
elif result["text"] == appearance_outcomes.doubleplay: elif result["outcome"] == appearance_outcomes.doubleplay:
self.get_pitcher().game_stats["outs_pitched"] += 2 self.get_pitcher().game_stats["outs_pitched"] += 2
self.outs += 2 self.outs += 2
self.bases[1] = None self.bases[1] = None
if self.outs < 3: if self.outs < 3:
scores_to_add += self.baserunner_check(defender, result) 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 self.get_batter().game_stats["rbis"] -= scores_to_add #remove the fake rbi from the player in advance
elif result["text"] == appearance_outcomes.fielderschoice or result["text"] == appearance_outcomes.groundout: elif result["outcome"] == appearance_outcomes.fielderschoice or result["outcome"] == appearance_outcomes.groundout:
self.get_pitcher().game_stats["outs_pitched"] += 1 self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1 self.outs += 1
if self.outs < 3: if self.outs < 3:
scores_to_add += self.baserunner_check(defender, result) scores_to_add += self.baserunner_check(result["defender"], result)
elif "advance" in result.keys(): elif "advance" in result.keys() or result["outcome"] == appearance_outcomes.sacrifice:
self.get_pitcher().game_stats["outs_pitched"] += 1 self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1 self.outs += 1
if self.outs < 3: if self.outs < 3:
if self.bases[3] is not None: if self.bases[3] is not None:
result["runner"] = self.bases[3].name
self.get_batter().game_stats["sacrifices"] += 1 self.get_batter().game_stats["sacrifices"] += 1
scores_to_add += self.baserunner_check(defender, result) scores_to_add += self.baserunner_check(result["defender"], result)
elif result["text"] == appearance_outcomes.strikeoutlooking or result["text"] == appearance_outcomes.strikeoutswinging: elif result["outcome"] == appearance_outcomes.strikeoutlooking or result["outcome"] == appearance_outcomes.strikeoutswinging:
self.get_pitcher().game_stats["outs_pitched"] += 1 self.get_pitcher().game_stats["outs_pitched"] += 1
self.outs += 1 self.outs += 1
self.get_batter().game_stats["strikeouts_taken"] += 1 self.get_batter().game_stats["strikeouts_taken"] += 1
@ -604,13 +639,24 @@ class game(object):
self.get_batter().game_stats["plate_appearances"] += 1 self.get_batter().game_stats["plate_appearances"] += 1
if self.voice.post_format != []:
format_list = []
for extra_format in self.voice.post_format:
if extra_format == "base":
format_list.append(base_string(result["base"]))
elif extra_format == "runner":
format_list.append(result["runner"])
self.voice.post_format = []
result["displaytext"] = result["displaytext"].format(*format_list)
if self.outs < 3: if self.outs < 3:
offense_team.score += scores_to_add #only add points if inning isn't over result["offense_team"].score += scores_to_add #only add points if inning isn't over
else: else:
scores_to_add = 0 scores_to_add = 0
self.get_batter().game_stats["rbis"] += scores_to_add self.get_batter().game_stats["rbis"] += scores_to_add
self.get_pitcher().game_stats["runs_allowed"] += scores_to_add self.get_pitcher().game_stats["runs_allowed"] += scores_to_add
offense_team.lineup_position += 1 #put next batter up result["offense_team"].lineup_position += 1 #put next batter up
self.choose_next_batter() self.choose_next_batter()
if self.outs >= 3: if self.outs >= 3:
self.flip_inning() self.flip_inning()
@ -666,7 +712,7 @@ class game(object):
def gamestate_update_full(self): def gamestate_update_full(self):
self.play_has_begun = True self.play_has_begun = True
attempts = self.thievery_attempts() attempts = self.thievery_attempts()
if attempts == False: if attempts == False or "twopart" in self.last_update[0]:
self.last_update = self.batterup() self.last_update = self.batterup()
else: else:
self.last_update = attempts self.last_update = attempts

View file

@ -1,4 +1,5 @@
from enum import Enum from enum import Enum
from random import randrange
class appearance_outcomes(Enum): class appearance_outcomes(Enum):
strikeoutlooking = "strikes out looking." strikeoutlooking = "strikes out looking."
@ -15,6 +16,375 @@ class appearance_outcomes(Enum):
homerun = "hits a dinger!" homerun = "hits a dinger!"
grandslam = "hits a grand slam!" grandslam = "hits a grand slam!"
class game_strings_base(object):
def __init__(self):
self.intro_counter = 2
self.post_format = []
default_format = ("defender",)
intro_formats = []
intro = [("","Automated Baseball Caster V16.38, now online."),("", "Play ball!")]
strikeoutlooking = ["strikes out looking."]
strikeoutswinging = ["strikes out swinging."]
groundout = ["grounds out to {}."]
flyout = ["flies out to {}."]
fielderschoice = ["reaches on fielder's choice. {} is out at {} base."]
doubleplay = ["grounds into a double play!"]
sacrifice = ["hits a sacrifice fly towards {}."]
walk = ["draws a walk."]
single = ["hits a single!"]
double = ["hits a double!"]
triple = ["hits a triple!"]
homerun = ["hits a dinger!"]
grandslam = ["hits a grand slam!"]
steal_caught = ["{} was caught stealing {} base by {}!"]
steal_success = ["{} steals {} base!"]
twoparts = []
diff_formats = {fielderschoice[0]: ("defender", "base_string"),
steal_success[0]: ("runner", "base_string"),
steal_caught[0]: ("runner", "base_string", "defender")}
no_formats = strikeoutlooking + strikeoutswinging + doubleplay + walk + single + double + triple + homerun + grandslam
def activate(self, lastupdate, currentupdate, game):
if "twopart" in lastupdate:
for key, value in lastupdate.items():
if key != "twopart":
currentupdate[key] = value
currentupdate["displaytext"] = self.format_gamestring(getattr(self, currentupdate["outcome"].name)[currentupdate["voiceindex"]][1], currentupdate)
elif "outcome" in currentupdate:
if self.check_for_twopart(getattr(self, currentupdate["outcome"].name)[currentupdate["voiceindex"]]):
currentupdate.update({
"twopart": True,
"displaytext": f"{currentupdate['batter']} {self.format_gamestring(getattr(self, currentupdate['outcome'].name)[currentupdate['voiceindex']][0], currentupdate)}"
})
else:
currentupdate["displaytext"] = f"{currentupdate['batter']} {self.format_gamestring(getattr(self, currentupdate['outcome'].name)[currentupdate['voiceindex']], currentupdate)}"
def check_for_twopart(self, gamestring):
return gamestring in self.twoparts
def format_gamestring(self, gamestring, update):
if gamestring in self.no_formats:
return gamestring
elif gamestring in self.diff_formats:
return gamestring.format(*self.parse_formats(self.diff_formats[gamestring], update))
else:
return gamestring.format(*self.parse_formats(self.default_format, update))
def parse_formats(self, format_tuple, update):
out_list = []
for string in format_tuple:
if string == "defender":
out_list.append(update['defender'].name)
elif string == "base_string":
self.post_format.append("base")
out_list.append("{}")
elif string == "batter":
out_list.append(update['batter'].name)
elif string == "pitcher":
out_list.append(update['pitcher'].name)
elif string == "fc_out" or string == "runner":
self.post_format.append("runner")
out_list.append("{}")
elif string == "defense_team":
out_list.append(update['defense_team'].name)
elif string == "offense_team":
out_list.append(update['offense_team'].name)
return tuple(out_list)
def activate_weather(self, lastupdate, currentupdate, game):
pass
def stealing(self, currentupdate, runner, base_string, defender, is_successful):
if is_successful:
index = randrange(0, len(self.steal_success))
text = self.steal_success[index]
else:
index = randrange(0, len(self.steal_caught))
text = self.steal_caught[index]
if text not in self.no_formats:
format_list = []
for format in self.diff_formats[text]:
if format == "runner":
format_list.append(runner)
elif format == "base_string":
format_list.append(base_string)
elif format == "defender":
format_list.append(defender)
currentupdate["steals"] = [text.format(*format_list)]
class TheGoddesses(game_strings_base):
def __init__(self):
self.intro_counter = 4
self.post_format = []
intro = [("💜", "This game is now blessed 💜"), ("🏳️‍⚧️","I'm Sakimori,"), ("🌺", "and i'm xvi! the sim16 goddesses are live and on-site, bringing you today's game."), ("🎆", "It's time to play ball!!")]
strikeoutlooking = ["watches a slider barely catch the outside corner. Hang up a ꓘ!",
"looks at a fastball paint the inside of the plate, and strikes out looking.",
"can't believe it as the ump calls strike 3 on a pitch that could have gone either way!",
"freezes up as a curveball catches the bottom edge of the zone. strike iii!"]
strikeoutswinging = ["swings at a changeup in the dirt for strike 3!",
"can't catch up to the fastball, and misses strike iii.",
"just misses the cutter and strikes out with a huge swing."]
groundout = ["hits a sharp grounder to {}! they throw to first and get the out easily.",
("tries to sneak a grounder between third base and the shortstop, but it's stopped by {} with a dive! They throw to first from their knees...", "and force the groundout!"),
"hits a routine ground ball to {} and is put out at first.",
("pulls a swinging bunt to {}, who rushes forward and throws to first...", "in time! {} is out!")]
flyout = [("shoots a line drive over {}'s head...", "They leap up and catch it! {} is out!!"),
"is out on a routine fly ball to {}.",
("hits a high fly ball deep to center! this one looks like a dinger...", "{} jumps up and steals it! {} is out!"),
"lines a ball to first, and it's caught by {} for the easy out.",
("hits a shallow fly to short center field! this might get down for a base hit...", "{} dives forward and catches it! We love to see it, 16.")]
fielderschoice = ["hits a soft grounder to shortstop, and {} forces {} out the short way. {} reaches on fielder's choice this time.",
"sharply grounds to third, and the throw over to {} forces {} out with a fielder's choice."]
doubleplay = ["grounds to {}. the throw to second makes it in time, as does the throw to first! {} turn the double play!",
("hits a grounder tailor-made for a double play right to {}.", "Two quick throws, and {} do indeed turn two!")]
sacrifice = [("hits a deep fly ball to right field, and {} looks ready to tag up...", "They beat the throw by a mile!"),
"sends a fly ball to deep center field, and {} comfortably tags up after the catch."]
walk = ["watches a changeup miss low, and takes first base for free.",
"is given a walk after a slider misses the zone for ball iv.",
("takes a close pitch that just misses inside, and is awarded a base on balls.", "saki. did you really just call it that? in [current year]?"),
"is walked on iv pitches.",
"jumps away from the plate as ball 4 misses far inside, just avoiding the hit-by-pitch and taking first on a walk."]
single = [("tries to sneak a grounder between third base and the shortstop, but it's stopped by {} with a dive! They throw to first from their knees...", "but they beat the throw! {} is safe at first with a hit."),
("shoots a line drive over {}'s head...", "They leap up but can't quite reach it! {} is safe at first with a single!!"),
("pulls a swinging bunt to {}, who rushes forward and throws to first...", "{} tags the bag just before the throw, and are rewarded with an infield single!"),
"hits a soft line drive over the infield, and makes it to first as it lands in the grass for a single.",
"shoots a comebacker right over second base and pulls into first safely, racking up a base hit.",
"hits a hard grounder into the right-side gap for a base hit."]
double = [("hits a shallow fly to short center field! this might get down for a base hit...", "{} dives for it, but can't quite get there! {} makes it around to second before the ball gets chased down. Good effort though!"),
"hits a fly ball into the outfield gap and pulls into second with a stand-up double.",
("hits a high fly ball deep to center! this one looks like a dinger...", "hell. it bounces off the wall, and that's a double."),
"shoots a line drive right down the third base line, just getting past {} for a double!"]
triple = ["hits a fly ball down the first base line! it lands fair, and gives {} enough time to round the bases all the way to third!!",
"stretches a line drive to the outfield gap from a double to a triple with a dive into third, just beating the throw!"]
homerun = [("hits a high fly ball deep to center! this one looks like a dinger...", "{} jumps up for the steal but can't get to it! Rack up another dinger for {}!"),
("hits a no-doubter over the right field wall!","Artemis won't be happy about that one 😅"),
"smacks a dinger to right field and takes a free trip around the basepaths.",
"hits a fly ball to deep left field, and it barely gets over the wall for a dinger!"]
grandslam = ["hits a fly ball to deep left field, and it barely gets over the wall for a GRAND SLAM!!!",
("hits a high fly ball deep to center! this one looks like a dinger...", "{} jumps up for the steal but can't get to it! {} gets a grand slam!!!")]
steal_success = ["{} takes {} with ease on a low changeup!",
"{} steals {} after a close throw from {} is just a moment too late!",
"{} tries to catch {} stealing, but a high throw means they pull off the steal at {} just in time."]
steal_caught = ["{} catches {} trying to steal {} with a laser throw!",
"{} tries to steal {}, but they can't beat the throw and get caught.",
"{} gets caught stealing easily with that throw from {}!"]
diff_formats = {groundout[3][1] : ("batter",),
flyout[0][1]: ("batter",), flyout[2][1]: ("defender", "batter"),
fielderschoice[0]: ("defender", "fc_out", "batter"), fielderschoice[1]: ("base_string", "fc_out"),
doubleplay[0]: ("defender", "defense_team"), doubleplay[1][1]: ("defense_team",),
sacrifice[0][0]: ("runner",), sacrifice[1]: ("runner",),
single[0][1]: ("batter",), single[1][1]: ("batter",), single[2][1]: ("batter",),
double[0][1]: ("defender", "batter"),
triple[0]: ("batter",),
homerun[0][1]: ("defender", "batter"),
grandslam[1][1]: ("defender", "batter"),
steal_success[0]: ("runner", "base_string"), steal_success[1]: ("runner", "base_string", "defender"), steal_success[2]: ("defender", "runner", "base_string"),
steal_caught[0]: ("defender", "runner", "base_string"), steal_caught[1]: ("runner", "base_string"), steal_caught[2]: ("runner", "defender")}
no_formats = strikeoutlooking + strikeoutswinging + walk + single[3:] + [flyout[4][0], sacrifice[0][1],
double[0][0], double[1], double[2][0], double[2][1], triple[1],
homerun[0][0], homerun[1][0], homerun[1][1], homerun[2:],
grandslam[0], grandslam[1][0]]
twoparts = [groundout[1], groundout[3], flyout[0], flyout[2], flyout[4], walk[2], doubleplay[1], single[0], single[1], single[2], sacrifice[0], double[0], double[2], homerun[0], homerun[1], grandslam[1]]
class TheNewGuy(game_strings_base):
def __init__(self):
self.intro_counter = 4
self.post_format = []
intro = [("👋","Hey, folks! First day, great to be here."),("👋", "Never played Baseball, or, uh, seen it, but Im really excited to learn along with you."),("👋", "Here we go! Uh, hows it go again…"),("👋", "Play baseball!")]
strikeoutlooking = ["watches the ball go right past em. Think youre supposed to hit it. And theyre out.",
"waits for the bat to start moving on its own, I guess? It doesnt, so… theyre out.",
"doesnt even try to go for the ball, apparently, and theyre out."]
strikeoutswinging = ["swings, but the ball is already past them! They were off by a mile! Theyre out.",
"swings three times, but never actually hits the ball. Out!",
"swings three times, and it looks like theyre headed home! I-in a bad way. As in theyre out."]
groundout = ["hits the ball! It rolls over to {}, whos throwing it to first, and… yep. Thats an out, I guess.",
"hits the ball! Nice!! And there they go, running towards first! Wait, since when did {} have the ball— and, whoops, yeah, theyre out at first.",
"hits the ball right onto the ground. It rolls over to {}, who nabs it and tosses it to first, and it looks like {}s out.",
"hits the ball over to the right side of the field. And it looks like {}s sending it right over to first, where {}s out."]
flyout = [("knocks the ball real hard right over {}.","They leap up and catch it! {} is out!!"),
"hits the ball super high up in the air! But it drops right into the hands of {}.",
("absolutely SMASHES that ball! Its gone!","Woah, hold on, nevermind. It looks like {} jumped up and grabbed it!"),
"bops the ball up in the air and over to {}. Worth a go, I guess?",
("winds up a real heavy hit, and the ball goes really fast!", "Not fast enough to faze {}, though, who does a spectacular leap over and nabs it out of the air.")]
fielderschoice = ["whacks the ball over to the left side of the baseball triangle, where {} sends {} back to their pit. {}s on base, though!",
("hits the ball onto the ground, where it rolls over to the second-and-a-half-base guard.","That guard puts a stop to {}s running, but they forgot about {}!")]
doubleplay = [("hits the ball over to {}, who picks it up and stops that runner at second.", "And theyre not done! They toss it to first and get {} out, too. Yikes."),
"hits the ball to {}, who gets that runner from first out before tossing it right back at first, and… wow. That went as poorly as it couldve. Theyre both out."]
sacrifice = [("does a little mini-hit, bumping the ball onto the field. {}s got it, and, yeah, theyre out at first.", "Wait, when did {} score? Oh, was that— that was clever! Very nice."),
"POUNDS the ball right up into the air! It lands right in the hands of {}, but {} takes the opportunity to stroll over to the one that gives points!"]
walk = ["watches the ball go right past them four times, and… gets to advance? Okay!",
("just stands there. The umpires calling it a ball, which… theyre all balls, arent they? Its baseball, not—", "Oh, uh, right. Theyre on first now. I guess."),
"hangs out for four throws, gets bored, and walks over to first. Didnt know you can do that, but good for them!",
"gets smacked with the ball! Yikes! Theyre limping over to first, so… were… were just going to keep going, then. Alright!"]
single = [("knocks the ball real hard right over {}.", "And get away with it, too, making it to first long before the ball does!"),
"hits the ball too hard for anyone to nab it and runs right over to first.",
"barely brushes up against the ball with the bat, and it lands pretty close to them. A bunch of folks scramble for it, but not before {} makes it to first!"]
double = ["hits the ball super hard, and while everyones scrambling for it theyre off to first! No, second!!",
"whacks the ball and gets out of there, making it to first and then second before anyone on the field can get the ball near them."]
triple = ["obliterates the ball and gets moving! Theyre at first! No, second! No, theyre at third! And... Oh, thats it, theyre done. Okay.",
"hits a three-base baseball whack! They try to go a little extra, but get scared into running back to third. Works."]
homerun = ["whacks the ball out of the park!! The crowds going wild as they run all the way around the baseball triangle and back to zeroth base!",
("absolutely SMASHES that ball! Its gone!", "And so are they, as they run all the bases and head right back home!"),
"hits a home run! Ooh, I know this one!"]
grandslam = ["hits the ball and chases all their friends home with them!",
"whacks the ball onto the ground reeeally far away. {} gets to it eventually, but not in time to stop ANYONE from making it home!!",
"hits a quadruple home run!"]
steal_success = ["runs to the next base too early!! You can do that??",
"is cheating!! They just ran to the next base and nobody even hit the ball!",
"gets bored of waiting and takes off, narrowly making it to the next base!"]
steal_caught = ["tries to run to the next base too early, and gets caught cheating!",
"sees if they can get away with dashing over to the next base. They cant, turns out.",
"tries running to the next base, but {}s ready for them. Out!"]
no_formats = strikeoutlooking + strikeoutswinging + walk + double + triple + steal_success + steal_caught[:2] + [flyout[2][0], flyout[4][0], fielderschoice[1][0], single[0][1], single[1], walk[1][0], walk[1][1],
homerun[0], homerun[1][0], homerun[1][1], homerun[2], grandslam[0], grandslam[2]]
diff_formats = {groundout[2]: ("defender", "batter"), groundout[3]: ("defender", "batter"),
flyout[0][1]: ("batter",),
fielderschoice[0]: ("defender", "fc_out", "batter"), fielderschoice[1][1]: ("fc_out", "batter"),
doubleplay[0][1]: ("batter",),
sacrifice[0][1]: ("runner",), sacrifice[1]: ("defender", "runner"),
single[2]: ("batter",),
steal_caught[2]: ("defender",)}
twoparts = [flyout[0], flyout[2], flyout[4], fielderschoice[1], doubleplay[0], sacrifice[0], walk[1], single[0], homerun[1]]
class TrespassOracle(game_strings_base):
def __init__(self):
self.intro_counter = 1
self.post_format = []
intro = [("👁‍🗨", "Trespass Oracle here for Channel 16, bringing you this full game live and ad-free thanks to the generous supporters on Patreon.")]
strikeoutlooking = ["punches out on that one. Strike 3!",
"stands by like a couch on the side of the road for that ball. Strike 3!",
"gets caught looking there. Can't take your eyes off the pitcher for a second."]
strikeoutswinging = ["whiffs on that last ball and they're outta here! Strike 3!",
"gets nothing but air on that ball. Strike 3!",
"squares up for a bunt, two strikes-- and it goes foul! It's gonna be a long walk back to the dugout for {}."]
groundout = ["rolls out the red carpet to {} on that ball. Easy out.",
"hits it into shallow right field there, where {} scoops the ball up and throws it to first. {} is outta here!",
"jumps on that pitch and makes a run for it, but {} throws them out at first!"]
flyout = ["hits a fly ball deep into centre field, and {} catches it!",
("hits a high fly into right field--", "{} dives-- and gets it! {} is out!"),
"hits the ball deep into left field-- but {} says it's not gonna be that easy, and robs them of a home run!",
("hits a high fly into right field--", "but {} dives into the stands to catch it! I've seen it, and I still don't believe what I just witnessed!")]
fielderschoice = ["hits it hard on the ground-- tough play. {} reaches on fielder's choice!",
"hits that one shallow, and {}'s made their choice: {} is outta here, but {} reaches!"]
doubleplay = ["grounds out into the double play! We really do hate to see it.",
"rolls out the red carpet to {}, and they turn the double play. They're making it look easy out there!",
"hits deep, but {} throws it into the double play there! Just a well-oiled defensive machine on the field tonight."]
sacrifice = [("hits that one deep, and {} tags up--", "They're safe! Shook hands with danger on that one!"),
"bunts on that one, letting {} come home on the sacrifice!",
"hits a sacrifice fly! {} tags up to keep this rally alive!"]
walk = ["draws a walk on that one. {} must not have wanted to risk it.",
"makes the walk to first.",
"gets hit by a beanball-- that one looks like it smarts! They're taking the long way round to First.",
"draws the walk there. Sometimes you've just gotta take what you can get."]
single = ["hits that one shallow, and just makes it before {} throws to first!",
"hits the ball deep, with {} running for it-- but {} dives to first in the knick of time! This league needs instant replay!",
"hits that one deep, but {} is on it like a hawk-- Don't get cocky, kid! {} puts on the brakes, safe at first with time to spare!"]
double = ["hits it deep and makes it to second with time to spare. The most dangerous base!",
"knocks that one into left field, swiftly rounds first-- and ends up safe at second!",
"nails the double and stops safe at second! You're halfway home, kid!"]
triple = ["puts an exclamation point on that one! Just enough time for {} to make it to third!",
"hits a high fly on that one-- {} runs for it but it hits the grass! {} makes it to third in the knick of time!",
"absolutely nails that one-- and safe at third! We love to see it!!",
"hits that one with authority and makes it to third! But they're still a long way from home!"]
homerun = ["hits one deep into left field-- No doubt about it, this one's a Home Run!",
"hits a high fly deep into right field-- and it's GONE! Home Run!",
"sends that one right into the stands!! HOME RUN! Wow, they are unbelievable!"]
grandslam = ["with the GRAND SLAM! AND THIS IS, INDEED, THE GREATEST NIGHT IN THE HISTORY OF OUR SPORT.",
"with a high fly into right field there-- and it's GONE! That's a GRAND SLAM!",
"with the GRAND SLAM! And if you had any dobuts about them, that should put them to rest right there!"]
steal_caught = ["{} was caught stealing {} base by {}!"]
steal_success = ["{} steals {} base!"]
no_formats = strikeoutlooking + strikeoutswinging[:2] + walk[1:] + double + triple[2:] + homerun + grandslam + [flyout[1][0] + flyout[3][0] + doubleplay[0] + sacrifice[0][1]]
diff_formats = {strikeoutswinging[2]: ("batter",),
groundout[1]: ("defender", "batter"),
flyout[1][1]: ("defender", "batter"),
fielderschoice[0]: ("batter",), fielderschoice[1]: ("defender", "runner", "batter"),
sacrifice[0][0]: ("runner",), sacrifice[1]: ("runner",), sacrifice[2]: ("runner",),
walk[0]: ("pitcher",),
single[1]: ("defender", "batter"), single[2]: ("defender", "batter"),
triple[0]: ("batter",), triple[1]: ("defender", "batter"),
steal_success[0]: ("runner", "base_string"),
steal_caught[0]: ("runner", "base_string", "defender")}
twoparts = [flyout[1], flyout[3], sacrifice[0]]
def all_voices():
return {"default": game_strings_base,
"The Goddesses": TheGoddesses,
"The New Guy": TheNewGuy,
"Trespass Oracle": TrespassOracle}
def weighted_voices(): #these are the ones accessible to random games
return [game_strings_base, TheGoddesses, TheNewGuy], [6, 4, 2]
def base_string(base): def base_string(base):
if base == 1: if base == 1:
return "first" return "first"

View file

@ -146,6 +146,7 @@ def save_league(league):
state_dic = { state_dic = {
"season" : league.season, "season" : league.season,
"day" : league.day, "day" : league.day,
"subs" : league.subbed_channels,
"last_weather_event" : league.last_weather_event_day, "last_weather_event" : league.last_weather_event_day,
"constraints" : league.constraints, "constraints" : league.constraints,
"game_length" : league.game_length, "game_length" : league.game_length,

View file

@ -5,6 +5,7 @@ from itertools import chain
from copy import deepcopy from copy import deepcopy
from games import team, game from games import team, game
from discord import Embed, Color from discord import Embed, Color
from uuid import uuid4
data_dir = "data" data_dir = "data"
league_dir = "leagues" league_dir = "leagues"
@ -21,6 +22,8 @@ class league_structure(object):
self.weather_override = None #set to a weather for league-wide weather effects self.weather_override = None #set to a weather for league-wide weather effects
self.last_weather_event_day = 0 self.last_weather_event_day = 0
self.weather_event_duration = 0 self.weather_event_duration = 0
self.postseason = True
self.subbed_channels = []
def setup(self, league_dic, division_games = 1, inter_division_games = 1, inter_league_games = 1, games_per_hour = 2): def setup(self, league_dic, division_games = 1, inter_division_games = 1, inter_league_games = 1, games_per_hour = 2):
self.league = league_dic # { subleague name : { division name : [team object] } } self.league = league_dic # { subleague name : { division name : [team object] } }
@ -514,7 +517,7 @@ class tournament(object):
self.day = None self.day = None
if id is None: if id is None:
self.id = random.randint(1111,9999) self.id = str(uuid4())
else: else:
self.id = id self.id = id
@ -651,4 +654,8 @@ def load_league_file(league_name):
this_league.last_weather_event_day = state_dic["last_weather_event"] this_league.last_weather_event_day = state_dic["last_weather_event"]
except: except:
this_league.last_weather_event_day = 0 this_league.last_weather_event_day = 0
try:
this_league.subbed_channels = state_dic["subs"]
except:
this_league.subbed_channels = []
return this_league return this_league

View file

@ -1,4 +1,4 @@
import asyncio, time, datetime, games, json, threading, jinja2, leagues, os, leagues, gametext import asyncio, time, datetime, games, json, threading, jinja2, leagues, os, leagues, gametext, logging
from leagues import league_structure from leagues import league_structure
from league_storage import league_exists from league_storage import league_exists
from flask import Flask, url_for, Response, render_template, request, jsonify, send_from_directory, abort from flask import Flask, url_for, Response, render_template, request, jsonify, send_from_directory, abort
@ -10,6 +10,10 @@ app.config['SECRET KEY'] = 'dev'
#url = "sakimori.space:5000" #url = "sakimori.space:5000"
#app.config['SERVER_NAME'] = url #app.config['SERVER_NAME'] = url
socketio = SocketIO(app) socketio = SocketIO(app)
socket_thread = None
log = logging.getLogger('werkzeug')
log.disabled = True
app.logger.disabled = True
# Serve React App # Serve React App
@app.route('/', defaults={'path': ''}) @app.route('/', defaults={'path': ''})
@ -90,11 +94,11 @@ def create_league():
for (key, min_val) in [ for (key, min_val) in [
('division_series', 1), ('division_series', 1),
('inter_division_series', 1), ('inter_division_series', 0),
('inter_league_series', 1) ('inter_league_series', 0)
]: ]:
if config[key] < min_val: if config[key] < min_val:
return jsonify({'status':'err_invalid_optiion_value', 'cause':key}), 400 return jsonify({'status':'err_invalid_option_value', 'cause':key}), 400
new_league = league_structure(config['name']) new_league = league_structure(config['name'])
new_league.setup( new_league.setup(
@ -126,7 +130,10 @@ def handle_new_conn(data):
def update_loop(): def update_loop():
global game_states global game_states
global socket_thread
while True: while True:
if socket_thread is not None:
socket_thread.join()
game_states = [] game_states = []
game_ids = iter(master_games_dic.copy().keys()) game_ids = iter(master_games_dic.copy().keys())
for game_id in game_ids: for game_id in game_ids:
@ -142,8 +149,13 @@ def update_loop():
state["home_score"] = this_game.teams["home"].score #update_pause = 0 state["home_score"] = this_game.teams["home"].score #update_pause = 0
#victory_lap = False #victory_lap = False
if not this_game.play_has_begun: #weather_emoji if not this_game.play_has_begun: #weather_emoji
state["update_emoji"] = "🎆" #weather_text if state["start_delay"] - this_game.voice.intro_counter > -1:
state["update_text"] = "Play ball!" #they also need a timestamp state["update_emoji"] = "🪑" #weather_text
state["update_text"] = "The broadcast booth is being prepared..." #they also need a timestamp
else:
state["update_emoji"] = this_game.voice.intro[-this_game.voice.intro_counter][0]
state["update_text"] = this_game.voice.intro[-this_game.voice.intro_counter][1]
this_game.voice.intro_counter -= 1
state["start_delay"] -= 1 state["start_delay"] -= 1
state["display_top_of_inning"] = state["top_of_inning"] state["display_top_of_inning"] = state["top_of_inning"]
@ -168,9 +180,9 @@ def update_loop():
if this_game.victory_lap and winning_team == this_game.teams['home'].name: if this_game.victory_lap and winning_team == this_game.teams['home'].name:
state["update_text"] = f"{winning_team} wins with a victory lap!" state["update_text"] = f"{winning_team} wins with a victory lap!"
elif winning_team == this_game.teams['home'].name: elif winning_team == this_game.teams['home'].name:
state["update_text"] = f"{winning_team} wins, shaming {this_game.teams['away'].name}!" state["update_text"] = f"{winning_team} wins with a partial victory lap!"
else: else:
state["update_text"] = f"{winning_team} wins!" state["update_text"] = f"{winning_team} wins on the road!"
state["pitcher"] = "-" state["pitcher"] = "-"
state["batter"] = "-" state["batter"] = "-"
@ -189,11 +201,13 @@ def update_loop():
elif state["update_pause"] != 1 and this_game.play_has_begun: elif state["update_pause"] != 1 and this_game.play_has_begun:
if "weather_message" in this_game.last_update[0].keys(): if "twopart" in this_game.last_update[0].keys():
state["update_emoji"] = "💬"
elif "weather_message" in this_game.last_update[0].keys():
state["update_emoji"] = this_game.weather.emoji state["update_emoji"] = this_game.weather.emoji
elif "ishit" in this_game.last_update[0].keys() and this_game.last_update[0]["ishit"]: elif "ishit" in this_game.last_update[0].keys() and this_game.last_update[0]["ishit"]:
state["update_emoji"] = "🏏" state["update_emoji"] = "🏏"
elif "text" in this_game.last_update[0].keys() and this_game.last_update[0]["text"] == gametext.appearance_outcomes.walk: elif "outcome" in this_game.last_update[0].keys() and this_game.last_update[0]["outcome"] == gametext.appearance_outcomes.walk:
state["update_emoji"] = "👟" state["update_emoji"] = "👟"
else: else:
state["update_emoji"] = "🗞" state["update_emoji"] = "🗞"
@ -209,22 +223,15 @@ def update_loop():
elif "text_only" in this_game.last_update[0].keys(): #this handles many weather messages elif "text_only" in this_game.last_update[0].keys(): #this handles many weather messages
state["update_text"] = this_game.last_update[0]["text"] state["update_text"] = this_game.last_update[0]["text"]
else: else:
updatestring = "" updatestring = this_game.last_update[0]["displaytext"]
punc = ""
if this_game.last_update[0]["defender"] != "":
punc = ". "
if "fc_out" in this_game.last_update[0].keys():
name, out_at_base_string = this_game.last_update[0]['fc_out']
updatestring = f"{this_game.last_update[0]['batter']} {this_game.last_update[0]['text'].value.format(name, out_at_base_string)} {this_game.last_update[0]['defender']}{punc}"
else:
updatestring = f"{this_game.last_update[0]['batter']} {this_game.last_update[0]['text'].value} {this_game.last_update[0]['defender']}{punc}"
if this_game.last_update[1] > 0: if this_game.last_update[1] > 0:
updatestring += f"{this_game.last_update[1]} runs scored!" updatestring += f" {this_game.last_update[1]} runs scored!"
state["update_text"] = updatestring state["update_text"] = f"{updatestring}"
if "twopart" not in this_game.last_update[0].keys():
this_game.weather.modify_atbat_message(this_game, state) this_game.weather.modify_atbat_message(this_game, state)
state["bases"] = this_game.named_bases() state["bases"] = this_game.named_bases()
@ -246,5 +253,7 @@ def update_loop():
state["update_pause"] -= 1 state["update_pause"] -= 1
socketio.emit("states_update", game_states) socket_thread = threading.Thread(target=socketio.emit, args=("states_update", game_states))
socket_thread.start()
#socketio.emit("states_update", game_states)
time.sleep(8) time.sleep(8)

View file

@ -5,10 +5,6 @@ import uuid
import onomancer import onomancer
DRAFT_SIZE = 20
REFRESH_DRAFT_SIZE = 4 # fewer players remaining than this and the list refreshes
DRAFT_ROUNDS = 13
Participant = namedtuple('Participant', ['handle', 'team']) Participant = namedtuple('Participant', ['handle', 'team'])
BOOKMARK = Participant(handle="bookmark", team=None) # keep track of start/end of draft round BOOKMARK = Participant(handle="bookmark", team=None) # keep track of start/end of draft round
@ -20,15 +16,19 @@ class Draft:
""" """
@classmethod @classmethod
def make_draft(cls): def make_draft(cls, teamsize, draftsize, minsize, pitchers):
draft = cls() draft = cls(teamsize, draftsize, minsize, pitchers)
return draft return draft
def __init__(self): def __init__(self, teamsize, draftsize, minsize, pitchers):
self.DRAFT_SIZE = draftsize
self.REFRESH_DRAFT_SIZE = minsize # fewer players remaining than this and the list refreshes
self.DRAFT_ROUNDS = teamsize
self.pitchers = pitchers
self._id = str(uuid.uuid4())[:6] self._id = str(uuid.uuid4())[:6]
self._participants = [] self._participants = []
self._active_participant = BOOKMARK # draft mutex self._active_participant = BOOKMARK # draft mutex
self._players = onomancer.get_names(limit=DRAFT_SIZE) self._players = onomancer.get_names(limit=self.DRAFT_SIZE)
self._round = 0 self._round = 0
@property @property
@ -68,7 +68,7 @@ class Draft:
self.advance_draft() self.advance_draft()
def refresh_players(self): def refresh_players(self):
self._players = onomancer.get_names(limit=DRAFT_SIZE) self._players = onomancer.get_names(limit=self.DRAFT_SIZE)
def advance_draft(self): def advance_draft(self):
""" """
@ -104,12 +104,12 @@ class Draft:
raise ValueError(f'Player `{player_name}` not in draft list') raise ValueError(f'Player `{player_name}` not in draft list')
del self._players[player['name']] del self._players[player['name']]
if len(self._players) <= REFRESH_DRAFT_SIZE: if len(self._players) <= self.REFRESH_DRAFT_SIZE:
self.refresh_players() self.refresh_players()
if self._round < DRAFT_ROUNDS: if self._round <= self.DRAFT_ROUNDS - self.pitchers:
self._active_participant.team.add_lineup(games.player(json.dumps(player))) self._active_participant.team.add_lineup(games.player(json.dumps(player)))
elif self._round == DRAFT_ROUNDS: else:
self._active_participant.team.add_pitcher(games.player(json.dumps(player))) self._active_participant.team.add_pitcher(games.player(json.dumps(player)))
self.advance_draft() self.advance_draft()

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
import random, math, roman import random, math, roman
from gametext import appearance_outcomes, base_string from gametext import appearance_outcomes, game_strings_base, base_string
class Weather: class Weather:
name = "Sunny" name = "Sunny"
@ -72,7 +72,7 @@ class SlightTailwind(Weather):
def activate(self, game, result): def activate(self, game, result):
if "mulligan" not in game.last_update[0].keys() and not result["ishit"] and result["text"] != appearance_outcomes.walk: if "mulligan" not in game.last_update[0].keys() and not result["ishit"] and result["outcome"] != appearance_outcomes.walk:
mulligan_roll_target = -((((game.get_batter().stlats["batting_stars"])-5)/6)**2)+1 mulligan_roll_target = -((((game.get_batter().stlats["batting_stars"])-5)/6)**2)+1
if random.random() > mulligan_roll_target and game.get_batter().stlats["batting_stars"] <= 5: if random.random() > mulligan_roll_target and game.get_batter().stlats["batting_stars"] <= 5:
result.clear() result.clear()
@ -90,7 +90,7 @@ class Starlight(Weather):
def activate(self, game, result): def activate(self, game, result):
if (result["text"] == appearance_outcomes.homerun or result["text"] == appearance_outcomes.grandslam): if (result["outcome"] == appearance_outcomes.homerun or result["outcome"] == appearance_outcomes.grandslam):
result["weather_message"] = True result["weather_message"] = True
dinger_roll = random.random() dinger_roll = random.random()
if "dragon" in game.get_batter().name.lower(): if "dragon" in game.get_batter().name.lower():
@ -190,7 +190,7 @@ class ThinnedVeil(Weather):
def activate(self, game, result): def activate(self, game, result):
if result["ishit"]: if result["ishit"]:
if result["text"] == appearance_outcomes.homerun or result["text"] == appearance_outcomes.grandslam: if result["outcome"] == appearance_outcomes.homerun or result["outcome"] == appearance_outcomes.grandslam:
result["veil"] = True result["veil"] = True
def modify_atbat_message(self, game, state): def modify_atbat_message(self, game, state):
@ -420,12 +420,47 @@ class Downpour(Weather):
def modify_top_of_inning_message(self, game, state): def modify_top_of_inning_message(self, game, state):
state["update_emoji"] = self.emoji state["update_emoji"] = self.emoji
if game.teams["away"].score >= self.target: #if the away team has met the target
if game.teams["home"].score == game.teams["away"].score: #if the teams are tied
state["update_text"] = "The gods demand a victor. Play on."
else:
state["update_text"] = f"The gods are pleased, but demand more from {game.teams['home'].name}. Take the field."
else:
state["update_text"] = "The gods are not yet pleased. Play continues through the storm." state["update_text"] = "The gods are not yet pleased. Play continues through the storm."
def modify_game_end_message(self, game, state): def modify_game_end_message(self, game, state):
state["update_emoji"] = self.emoji state["update_emoji"] = self.emoji
state["update_text"] = f"{self.target} runs are reached, pleasing the gods. The storm clears." state["update_text"] = f"{self.target} runs are reached, pleasing the gods. The storm clears."
class SummerMist(Weather):
name = "Summer Mist"
emoji = "🌁"
duration_range = [1,3]
substances = ["yellow mustard", "cat fur", "dread", "caramel", "nacho cheese", "mud", "dirt", "justice", "a green goo", "water, probably", "antimatter", "something not of this world", "live ferrets", "snow", "leaves",
"yarn", "seaweed", "sawdust", "stardust", "code fragments", "milk", "lizards", "a large tarp", "feathers"]
def __init__(self, game):
self.missing_players = {game.teams["home"].name: None, game.teams["away"].name: None}
self.text = ""
def activate(self, game, result):
if result["outcome"] in [appearance_outcomes.flyout, appearance_outcomes.groundout, appearance_outcomes.sacrifice]:
roll = random.random()
if roll < .3: #get lost
result["mist"] = True
self.text = f" {result['batter'].name} gets lost in the mist on the way back to the dugout."
if self.missing_players[result["offense_team"].name] is not None:
self.text += f" {self.missing_players[result['offense_team'].name].name} wanders back, covered in {random.choice(self.substances)}!"
result["offense_team"].lineup[result["offense_team"].lineup_position % len(result["offense_team"].lineup)] = self.missing_players[result["offense_team"].name]
else:
result["offense_team"].lineup.pop(result["offense_team"].lineup_position % len(result["offense_team"].lineup))
self.missing_players[result["offense_team"].name] = result["batter"]
def modify_atbat_message(self, game, state):
if "mist" in game.last_update[0]:
state["update_emoji"] = self.emoji
state["update_text"] += self.text
self.text = ""
def all_weathers(): def all_weathers():
weathers_dic = { weathers_dic = {
@ -442,31 +477,33 @@ def all_weathers():
"Meteor Shower" : MeteorShower, "Meteor Shower" : MeteorShower,
"Hurricane" : Hurricane, "Hurricane" : Hurricane,
"Tornado" : Tornado, "Tornado" : Tornado,
"Torrential Downpour" : Downpour "Torrential Downpour" : Downpour,
"Summer Mist" : SummerMist
} }
return weathers_dic return weathers_dic
class WeatherChains(): class WeatherChains():
light = [SlightTailwind, Twilight, Breezy, Drizzle] #basic starting points for weather, good comfortable spots to return to light = [SlightTailwind, Twilight, Breezy, Drizzle, SummerMist] #basic starting points for weather, good comfortable spots to return to
magic = [Twilight, ThinnedVeil, MeteorShower, Starlight] #weathers involving breaking the fabric of spacetime magic = [Twilight, ThinnedVeil, MeteorShower, Starlight] #weathers involving breaking the fabric of spacetime
sudden = [Tornado, Hurricane, Twilight, Starlight, Midnight, Downpour] #weathers that always happen and leave over 1-3 games sudden = [Tornado, Hurricane, Twilight, Starlight, Midnight, Downpour] #weathers that always happen and leave over 1-3 games
disaster = [Hurricane, Tornado, Downpour, Blizzard] #storms disaster = [Hurricane, Tornado, Downpour, Blizzard] #storms
aftermath = [Midnight, Starlight, MeteorShower] #calm epilogues aftermath = [Midnight, Starlight, MeteorShower, SummerMist] #calm epilogues
dictionary = { dictionary = {
#Supernova : (magic + sudden + disaster, None), supernova happens leaguewide and shouldn't need a chain, but here just in case #Supernova : (magic + sudden + disaster, None), supernova happens leaguewide and shouldn't need a chain, but here just in case
Midnight : ([SlightTailwind, Breezy, Drizzle, Starlight, MeteorShower, HeatWave],[2,2,2,4,4,1]), Midnight : ([SlightTailwind, Breezy, Drizzle, Starlight, MeteorShower, HeatWave, SummerMist],[2,2,2,4,4,1,2]),
SlightTailwind : ([Breezy, Drizzle, Tornado], [3,3,1]), SlightTailwind : ([Breezy, Drizzle, Tornado], [3,3,1]),
Blizzard : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]), Blizzard : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]),
Twilight : ([ThinnedVeil, Midnight, MeteorShower, SlightTailwind], [2,4,2,1]), Twilight : ([ThinnedVeil, Midnight, MeteorShower, SlightTailwind, SummerMist], [2,4,2,1,2]),
ThinnedVeil : (light, None), ThinnedVeil : (light, None),
HeatWave : ([Tornado, Hurricane, SlightTailwind, Breezy],[4,4,1,1]), HeatWave : ([Tornado, Hurricane, SlightTailwind, Breezy, SummerMist],[4,4,1,1,2]),
Drizzle : ([Hurricane, Downpour, Blizzard],[2,2,1]), Drizzle : ([Hurricane, Downpour, Blizzard],[2,2,1]),
Breezy : ([Drizzle, HeatWave, Blizzard, Tornado], [3,3,1,1]), Breezy : ([Drizzle, HeatWave, Blizzard, Tornado], [3,3,1,1]),
Starlight : ([SlightTailwind, Twilight, Breezy, Drizzle, ThinnedVeil, HeatWave], None), Starlight : ([SlightTailwind, Twilight, Breezy, Drizzle, ThinnedVeil, HeatWave], None),
MeteorShower : ([Starlight, ThinnedVeil, HeatWave], None), MeteorShower : ([Starlight, ThinnedVeil, HeatWave], None),
Hurricane : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]), Hurricane : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]),
Tornado : ([Midnight, Starlight, MeteorShower, Twilight, Downpour],[2,2,2,2,4]), Tornado : ([Midnight, Starlight, MeteorShower, Twilight, Downpour],[2,2,2,2,4]),
SummerMist : ([Drizzle, Breezy, Hurricane, Downpour],[2, 1, 1, 1]),
Downpour : (aftermath, None) Downpour : (aftermath, None)
} }