diff --git a/games.py b/games.py index 42b3473..e6f5c7e 100644 --- a/games.py +++ b/games.py @@ -222,7 +222,7 @@ class game(object): else: self.max_innings = config()["default_length"] self.bases = {1 : None, 2 : None, 3 : None} - self.weather = weather.Weather() + self.weather = weather.Weather(self) self.current_batter = None def choose_next_batter(self): @@ -261,38 +261,34 @@ class game(object): outcome["batter"] = batter outcome["defender"] = "" - bat_stat = random_star_gen("batting_stars", batter) - pitch_stat = random_star_gen("pitching_stars", pitcher) + player_rolls = {} + player_rolls["bat_stat"] = random_star_gen("batting_stars", batter) + player_rolls["pitch_stat"] = random_star_gen("pitching_stars", pitcher) - bat_stat, pitch_stat = self.weather.modify_stats_preroll(bat_stat, pitch_stat) + self.weather.modify_atbat_stats(player_rolls) - pb_system_stat = (random.gauss(1*math.erf((bat_stat - pitch_stat)*1.5)-1.8,2.2)) - hitnum = random.gauss(2*math.erf(bat_stat/4)-1,3) + 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) - if self.weather.name == "Twilight": - error_line = - (math.log(defender.stlats["defense_stars"] + 1)/50) + 1 - error_roll = random.random() - if error_roll > error_line: - outcome["error"] = True - outcome["defender"] = defender - pb_system_stat = 0.1 + self.weather.modify_atbat_roll(outcome, roll, defender) - if pb_system_stat <= 0: + if roll["pb_system_stat"] <= 0: outcome["ishit"] = False fc_flag = False - if hitnum < -1.5: + if roll["hitnum"] < -1.5: outcome["text"] = random.choice([appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging]) - elif hitnum < 1: + elif roll["hitnum"] < 1: outcome["text"] = appearance_outcomes.groundout outcome["defender"] = defender - elif hitnum < 4: + elif roll["hitnum"] < 4: outcome["text"] = appearance_outcomes.flyout outcome["defender"] = defender else: outcome["text"] = appearance_outcomes.walk - if self.bases[1] is not None and 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["defender"] = "" @@ -309,20 +305,20 @@ class game(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 <= hitnum and 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["defender"] = "" - if 2.5 <= 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 if self.bases[2] is not None or self.bases[3] is not None: outcome["advance"] = True else: outcome["ishit"] = True - if hitnum < 1: + if roll["hitnum"] < 1: outcome["text"] = appearance_outcomes.single - elif hitnum < 2.85 or "error" in outcome.keys(): + elif roll["hitnum"] < 2.85 or "error" in outcome.keys(): outcome["text"] = appearance_outcomes.double - elif hitnum < 3.1: + elif roll["hitnum"] < 3.1: outcome["text"] = 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: @@ -339,13 +335,16 @@ class game(object): 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: - run_stars = random_star_gen("baserunning_stars", baserunner)*config()["stolen_base_chance_mod"] - if self.weather.name == "Midnight": - run_stars = run_stars*2 - def_stars = random_star_gen("defense_stars", self.get_pitcher()) - if run_stars >= (def_stars - 1.5): #if baserunner isn't worse than pitcher + 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 stats["run_stars"] >= (stats["def_stars"] - 1.5): #if baserunner isn't worse than pitcher roll = random.random() - if roll >= (-(((run_stars+1)/14)**2)+1): #plug it into desmos or something, you'll see + 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: diff --git a/main_controller.py b/main_controller.py index b513322..251e1c3 100644 --- a/main_controller.py +++ b/main_controller.py @@ -3,6 +3,7 @@ from leagues import league_structure from league_storage import league_exists from flask import Flask, url_for, Response, render_template, request, jsonify, send_from_directory, abort from flask_socketio import SocketIO, emit +from gametext import base_string import database as db app = Flask("the-prestige", static_folder='simmadome/build') @@ -156,7 +157,7 @@ def update_loop(): state["display_inning"] -= 1 state["display_top_of_inning"] = False - if state["update_pause"] == 1: + if state["update_pause"] == 1: #generate the top of the inning message before displaying the at bat result state["update_emoji"] = "🍿" if this_game.over: state["display_inning"] -= 1 @@ -222,8 +223,8 @@ def update_loop(): if "fc_out" in this_game.last_update[0].keys(): - name, 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, base_string)} {this_game.last_update[0]['defender']}{punc}" + 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: @@ -234,7 +235,7 @@ def update_loop(): if "veil" in this_game.last_update[0].keys(): state["update_emoji"] = "🌌" - state["update_text"] += f" {this_game.last_update[0]['batter']}'s will manifests on {gametext.base_string(this_game.last_update[1])} base." + state["update_text"] += f" {this_game.last_update[0]['batter']}'s will manifests on {base_string(this_game.last_update[1])} base." elif "error" in this_game.last_update[0].keys(): state["update_emoji"] = "👻" state["update_text"] = f"{this_game.last_update[0]['batter']}'s hit goes ethereal, and {this_game.last_update[0]['defender']} can't catch it! {this_game.last_update[0]['batter']} reaches base safely." diff --git a/the_prestige.py b/the_prestige.py index 6d63519..cdf95b8 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -1398,7 +1398,7 @@ async def watch_game(channel, newgame, user = None, league = None): def prepare_game(newgame, league = None, weather_name = None): if weather_name is None: weathers = weather.all_weathers() - newgame.weather = weathers[random.choice(list(weathers.keys()))]() + newgame.weather = weathers[random.choice(list(weathers.keys()))](newgame) state_init = { "away_name" : newgame.teams['away'].name, @@ -1418,9 +1418,6 @@ def prepare_game(newgame, league = None, weather_name = None): else: state_init["is_league"] = True - if newgame.weather.name == "Heavy Snow": - newgame.weather.counter_away = random.randint(0,len(newgame.teams['away'].lineup)-1) - newgame.weather.counter_home = random.randint(0,len(newgame.teams['home'].lineup)-1) return newgame, state_init async def start_tournament_round(channel, tourney, seeding = None): diff --git a/weather.py b/weather.py index 4087492..a38f478 100644 --- a/weather.py +++ b/weather.py @@ -1,12 +1,11 @@ import random +import math from gametext import appearance_outcomes class Weather: - def __init__(self): + def __init__(self, game): self.name = "Sunny" self.emoji = "🌞" + "\uFE00" - self.counter_away = 0 - self.counter_home = 0 def __str__(self): return f"{self.emoji} {self.name}" @@ -15,43 +14,44 @@ class Weather: # activates after the batter calculation. modify result, or just return another thing pass - def modify_stats_preroll(self, bat_stat, pitch_stat): # ugly - # Activates before batting and pitch - return bat_stat, pitch_stat - def on_flip_inning(self, game): pass def on_choose_next_batter(self, game): pass + def modify_steal_stats(self, roll): + pass + + def modify_atbat_stats(self, player_rolls): + # Activates before batting + pass + + def modify_atbat_roll(self, outcome, roll, defender): + pass + class Supernova(Weather): # todo - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Supernova" self.emoji = "🌟" + "\uFE00" - def activate(self, game, result): - pass - def modify_stats_preroll(self, bat_stat, pitch_stat): - if self.weather.name == "Supernova": - pitch_stat = pitch_stat * 0.9 + def modify_atbat_stats(self, roll): + roll["pitch_stat"] *= 0.9 class Midnight(Weather): # todo - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Midnight" self.emoji = "🕶" + "\uFE00" - def activate(self, game, result): - pass + + def modify_steal_stats(self, roll): + roll["run_stars"] *= 2 class SlightTailwind(Weather): - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Slight Tailwind" self.emoji = "🏌️‍♀️" + "\uFE00" + def activate(self, game, result): - if game.top_of_inning: offense_team = game.teams["away"] weather_count = self.counter_away @@ -67,10 +67,11 @@ class SlightTailwind(Weather): result["mulligan"] = True class HeavySnow(Weather): - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Heavy Snow" self.emoji = "❄" + "\uFE00" + self.counter_away = random.randint(0,len(game.teams['away'].lineup)-1) + self.counter_home = random.randint(0,len(game.teams['home'].lineup)-1) def activate(self, game, result): if game.top_of_inning: @@ -107,16 +108,23 @@ class HeavySnow(Weather): game.current_batter = bat_team.pitcher class Twilight(Weather): - def __init__(self): - super().__init__() + def __init__(self,game): self.name = "Twilight" self.emoji = "👻" + "\uFE00" def activate(self, game, result): pass + + def modify_atbat_roll(self, outcome, roll, defender): + error_line = - (math.log(defender.stlats["defense_stars"] + 1)/50) + 1 + error_roll = random.random() + if error_roll > error_line: + outcome["error"] = True + outcome["defender"] = defender + roll["pb_system_stat"] = 0.1 + class ThinnedVeil(Weather): - def __init__(self): - super().__init__() + def __init__(self,game): self.name = "Thinned Veil" self.emoji = "🌌" + "\uFE00" @@ -126,22 +134,21 @@ class ThinnedVeil(Weather): result["veil"] = True class HeatWave(Weather): - def __init__(self): - super().__init__() + def __init__(self,game): self.name = "Heat Wave" self.emoji = "🌄" + "\uFE00" - self.counter_away = random.randint(2,4) - self.counter_home = random.randint(2,4) + self.counter_away = -1# random.randint(2,4) + self.counter_home = -1 # random.randint(2,4) def on_flip_inning(self, game): current_pitcher = game.get_pitcher() if game.top_of_inning: - bat_team = game.teams["away"] - counter = self.counter_away - else: bat_team = game.teams["home"] counter = self.counter_home + else: + bat_team = game.teams["away"] + counter = self.counter_away should_change_pitcher = False if game.inning >= counter: @@ -158,8 +165,7 @@ class HeatWave(Weather): tries += 1 class Drizzle(Weather): - def __init__(self): - super().__init__() + def __init__(self,game): self.name = "Drizzle" self.emoji = "🌧" @@ -173,9 +179,10 @@ class Drizzle(Weather): game.bases[2] = lineup[(game.teams[next_team].lineup_position-1) % len(lineup)] class Sun2(Weather): - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Sun 2" + + def activate(self, game): for teamtype in game.teams: team = game.teams[teamtype] @@ -184,15 +191,15 @@ class Sun2(Weather): # no win counting yet :( result.clear() result.update({ - "text": "The {} collect 10! Sun 2 smiles.".format(team.name), + "text": "The {} collect 10! Sun 2 smiles.".format(team.name), "text_only": True, }) class NameSwappyWeather(Weather): - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Literacy" self.activation_chance = 0.01 + def activate(self, game): if random.random() < self.activation_chance: teamtype = random.choice(["away","home"]) @@ -220,11 +227,11 @@ class NameSwappyWeather(Weather): }) class Feedback(Weather): - def __init__(self): - super().__init__() + def __init__(self, game): self.name = "Feedback" self.activation_chance = 0.01 self.swap_batter_vs_pitcher_chance = 0.8 + def activate(self, game, result): if random.random() < self.activation_chance: # feedback time @@ -261,8 +268,8 @@ def all_weathers(): #"Midnight": Midnight, #"Slight Tailwind": SlightTailwind, "Heavy Snow": HeavySnow, -# "Twilight" : Twilight, -# "Thinned Veil" : ThinnedVeil, + # "Twilight" : Twilight, # works + # "Thinned Veil" : ThinnedVeil, # works "Heat Wave" : HeatWave, "Drizzle" : Drizzle, # works # Sun2,