diff --git a/README.md b/README.md index 0dc9033..144e9cd 100644 --- a/README.md +++ b/README.md @@ -170,8 +170,11 @@ accepting pull requests, check the issues for to-dos. - drizzle 🌧: causes each inning to start with the previous inning's final batter on second base. - heat wave 🌄: occasionally causes pitchers to be relieved by a random player from the lineup. - breezy 🎐: occasionally swaps letters of a player's name, altering their name for the remainder of the game and changing their stats. - - starlight 🌃: current patch weather, effects will be revealed the next time weathers are added. - - meteor shower 🌠: current patch weather, effects will be revealed the next time weathers are added. + - starlight 🌃: the stars are displeased with dingers and will cancel most of them out by pulling them foul. + - meteor shower 🌠: has a chance to warp runners on base to none base causing them to score. + - hurricane 🌀: current patch weather, its effects will be revealed when new weathers are added. + - tornado 🌪: current patch weather, its effects will be revealed when new weathers are added. + - torrential downpour ⛈: current patch weather, its effects will be revealed when new weathers are added. ## patreon! diff --git a/database.py b/database.py index fe563f5..69afb31 100644 --- a/database.py +++ b/database.py @@ -371,7 +371,7 @@ def add_team_obl(team): conn.commit() conn.close() -def save_obl_results(winning_team, losing_team): +def save_obl_results(winning_team, losing_team, xvi_team = None): conn = create_connection() if conn is not None: c=conn.cursor() @@ -392,7 +392,22 @@ def save_obl_results(winning_team, losing_team): obl_points += 1 c.execute("UPDATE one_big_league SET teams_beaten_list = ?, current_opponent_pool = ?, obl_points = ? WHERE team_name = ?", (list_to_newline_string(beaten_teams), list_to_newline_string(opponent_teams), obl_points, winning_team.name)) + conn.commit() + conn.close() + if xvi_team is not None: + add_obl_point(xvi_team) + return + +def add_obl_point(team): + conn = create_connection() + if conn is not None: + c=conn.cursor() + + c.execute("SELECT obl_points FROM one_big_league WHERE team_name = ?", (team.name,)) + xvi_obl_points = c.fetchone()[0] + xvi_obl_points += 1 + c.execute("UPDATE one_big_league SET obl_points = ? WHERE team_name = ?", (xvi_obl_points, team.name)) conn.commit() conn.close() return @@ -403,15 +418,15 @@ def get_obl_stats(team, full = False): c=conn.cursor() opponents_string = None while opponents_string is None: - c.execute("SELECT teams_beaten_list, current_opponent_pool, rival_name FROM one_big_league WHERE team_name = ?", (team.name,)) + c.execute("SELECT teams_beaten_list, current_opponent_pool, rival_name, obl_points FROM one_big_league WHERE team_name = ?", (team.name,)) try: - beaten_string, opponents_string, rival_name = c.fetchone() + beaten_string, opponents_string, rival_name, obl_points = c.fetchone() except TypeError: #add team to OBL + obl_points = 0 add_team_obl(team) beaten_teams = newline_string_to_list(beaten_string) opponent_teams = opponents_string - obl_points = len(beaten_teams) teams_list = [name for name, points in obl_leaderboards()] rank = teams_list.index(team.name) + 1 diff --git a/games.py b/games.py index 88a22be..84dae73 100644 --- a/games.py +++ b/games.py @@ -635,7 +635,13 @@ class game(object): if self.inning > self.max_innings and self.teams["home"].score != self.teams["away"].score: #game over self.over = True if self.max_innings >= 9: - 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"]) + if self.teams["home"].score == 16: + this_xvi_team = self.teams["home"] + elif self.teams["away"].score == 16: + this_xvi_team = self.teams["away"] + else: + 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) def end_of_game_report(self): diff --git a/league_storage.py b/league_storage.py index 0dcee16..443aead 100644 --- a/league_storage.py +++ b/league_storage.py @@ -146,14 +146,16 @@ def save_league(league): state_dic = { "season" : league.season, "day" : league.day, + "last_weather_event" : league.last_weather_event_day, "constraints" : league.constraints, - "schedule" : league.schedule, "game_length" : league.game_length, "series_length" : league.series_length, "games_per_hour" : league.games_per_hour, "owner" : league.owner, "champion" : league.champion, - "historic" : league.historic + "schedule" : league.schedule, + "forecasts" : league.weather_forecast, + "historic" : league.historic } with open(os.path.join(data_dir, league_dir, league.name, f"{league.name}.state"), "w") as state_file: json.dump(state_dic, state_file, indent=4) diff --git a/leagues.py b/leagues.py index f4dd135..845aa8d 100644 --- a/leagues.py +++ b/leagues.py @@ -1,5 +1,6 @@ import time, asyncio, json, jsonpickle, random, math, os import league_storage as league_db +from weather import WeatherChains, all_weathers from itertools import chain from copy import deepcopy from games import team, game @@ -16,6 +17,10 @@ class league_structure(object): self.season = 1 self.autoplay = -1 self.champion = None + self.weather_forecast = {} + self.weather_override = None #set to a weather for league-wide weather effects + self.last_weather_event_day = 0 + self.weather_event_duration = 0 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] } } @@ -32,6 +37,9 @@ class league_structure(object): self.game_length = None self.active = False self.games_per_hour = games_per_hour + + + def season_reset(self): self.season += 1 @@ -256,6 +264,33 @@ class league_structure(object): scheduled = True day += 1 + #now do forecasts + for this_team in self.teams_in_league(): + start_weather = WeatherChains.starting_weather() #gets a random starting weather class + start_weather_duration = random.randint(start_weather.duration_range[0], start_weather.duration_range[1]) + self.weather_forecast[this_team.name] = [start_weather.name] * start_weather_duration + forecasted_days = [] + for i in range(start_weather_duration, len(self.schedule.keys())): + if i not in forecasted_days: + prev_weather = self.weather_forecast[this_team.name][i-1] #get last weather name + next_weather = WeatherChains.chain_weather(all_weathers()[prev_weather]) #ask weatherchains for next weather + next_weather_duration = random.randint(next_weather.duration_range[0], next_weather.duration_range[1]) + self.weather_forecast[this_team.name] += [next_weather.name] * next_weather_duration + forecasted_days = [n for n in range(i, i + next_weather_duration)] + + def new_weathers_midseason(self, team_name): #generate new forecast for specific team + start_weather = WeatherChains.starting_weather() #gets a random starting weather class + start_weather_duration = self.day - 1 if self.day > 1 else random.randint(start_weather.duration_range[0], start_weather.duration_range[1]) + self.weather_forecast[team_name] = [start_weather.name] * start_weather_duration + forecasted_days = [] + for i in range(start_weather_duration, len(self.schedule.keys())): + if i not in forecasted_days: + prev_weather = self.weather_forecast[team_name][i-1] #get last weather name + next_weather = WeatherChains.chain_weather(all_weathers()[prev_weather]) #ask weatherchains for next weather + next_weather_duration = random.randint(next_weather.duration_range[0], next_weather.duration_range[1]) + self.weather_forecast[team_name] += [next_weather.name] * next_weather_duration + forecasted_days = [n for n in range(i, i + next_weather_duration)] + def division_standings(self, division, standings): def sorter(team_in_list): if team_in_list[2] == 0 and team_in_list[1] == 0: @@ -433,6 +468,32 @@ class league_structure(object): this_embed.add_field(name=player_name, value=content_string, inline=False) return this_embed + def get_weather_now(self, team_name): + if self.weather_override is None or self.weather_event_duration <= 0: #if no override set or if past event expired + if self.day < len(self.weather_forecast[team_name]) and random.random() < 0.08: #8% chance the forcast was wrong + if random.random() < 0.33: + return all_weathers()[self.weather_forecast[team_name][self.day]] #next weather came a day early + elif random.random() < 0.66: + return random.choice(WeatherChains.parent_weathers(all_weathers()[self.weather_forecast[team_name][self.day]])) #pivot to different parent weather to lead in + else: + return WeatherChains.chain_weather(all_weathers()[self.weather_forecast[team_name][self.day - 1]]) #jump to a child weather for a day + return all_weathers()[self.weather_forecast[team_name][self.day - 1]] + else: + if self.weather_event_duration == 1 and random.random() < 0.1: #once per weather event, roll for forecast regen + self.new_weathers_midseason(team_name) + return self.weather_override + + def weather_event_check(self): #2 for new event, 1 for continued event, 0 for no event + if self.day - self.last_weather_event_day > 20: #arbitrary cooldown between weather events + if random.random() < 0.05: #5% chance for weather event? + self.weather_override = all_weathers()["Supernova"] + self.last_weather_event_day = self.day + self.weather_event_duration = random.randint(self.weather_override.duration_range[0], self.weather_override.duration_range[1]) + return 2 + else: + self.weather_event_duration -= 1 + return 1 if self.weather_event_duration > 0 else 0 + class tournament(object): def __init__(self, name, team_dic, series_length = 5, finals_series_length = 7, max_innings = 9, id = None, secs_between_games = 300, secs_between_rounds = 600): @@ -579,4 +640,15 @@ def load_league_file(league_name): this_league.champion = state_dic["champion"] except: this_league.champion = None + try: + this_league.weather_forecast = state_dic["forecasts"] #handles legacy leagues + except: + this_league.weather_forecast = {} + for this_team in this_league.teams_in_league(): #give them all fresh forecasts starting at current day + this_league.new_weathers_midseason(this_team.name) + save_league(this_league) + try: + this_league.last_weather_event_day = state_dic["last_weather_event"] + except: + this_league.last_weather_event_day = 0 return this_league \ No newline at end of file diff --git a/main_controller.py b/main_controller.py index 8855788..7189bcf 100644 --- a/main_controller.py +++ b/main_controller.py @@ -148,6 +148,8 @@ def update_loop(): state["display_top_of_inning"] = state["top_of_inning"] + this_game.weather.modify_gamestate(this_game, state) + if state["start_delay"] <= 0: if this_game.top_of_inning != state["top_of_inning"]: state["update_pause"] = 2 @@ -171,6 +173,8 @@ def update_loop(): state["update_text"] = f"{winning_team} wins!" state["pitcher"] = "-" state["batter"] = "-" + + this_game.weather.modify_game_end_message(this_game, state) else: if this_game.top_of_inning: state["update_text"] = f"Top of {this_game.inning}. {this_game.teams['away'].name} batting!" diff --git a/the_prestige.py b/the_prestige.py index 4c9a42c..2a773fe 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -1043,7 +1043,10 @@ class LeagueScheduleCommand(Command): schedule_text = "" teams = league.team_names_in_league() for game in league.schedule[str(current_series+day)]: - schedule_text += f"**{game[0]}** @ **{game[1]}**\n" + emojis = "" + for day_offset in range((current_series+day - 1)*league.series_length, (current_series+day)*(league.series_length)): + emojis += weather.all_weathers()[league.weather_forecast[game[1]][day_offset]].emoji + " " + schedule_text += f"**{game[0]}** @ **{game[1]}** {emojis}\n" teams.pop(teams.index(game[0])) teams.pop(teams.index(game[1])) if len(teams) > 0: @@ -1080,9 +1083,14 @@ class LeagueTeamScheduleCommand(Command): for day in days: if str(current_series+day) in league.schedule.keys(): schedule_text = "" + + for game in league.schedule[str(current_series+day)]: if team.name in game: - schedule_text += f"**{game[0]}** @ **{game[1]}**" + emojis = "" + for day_offset in range((current_series+day - 1)*league.series_length, (current_series+day)*(league.series_length)): + emojis += weather.all_weathers()[league.weather_forecast[game[1]][day_offset]].emoji + " " + schedule_text += f"**{game[0]}** @ **{game[1]}** {emojis}" if schedule_text == "": schedule_text += "Resting" sched_embed.add_field(name=f"Days {((current_series+day-1)*league.series_length) + 1} - {(current_series+day)*(league.series_length)}", value=schedule_text, inline = False) @@ -2119,7 +2127,9 @@ def game_over_embed(game): title_string += ".\n" winning_team = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name - winstring = f"{game.teams['away'].score} to {game.teams['home'].score}\n" + homestring = str(game.teams["home"].score) + ("☄" if game.teams["home"].score == 16 else "") + awaystring = ("☄" if game.teams["away"].score == 16 else "") + str(game.teams["away"].score) + winstring = f"{awaystring} to {homestring}\n" if game.victory_lap and winning_team == game.teams['home'].name: winstring += f"{winning_team} wins with a victory lap!" elif winning_team == game.teams['home'].name: @@ -2151,6 +2161,8 @@ async def start_league_day(channel, league, partial = False): else: game_length = league.game_length + weather_check_result = league.weather_event_check() + for pair in games_to_start: if pair[0] is not None and pair[1] is not None: away = get_team_fuzzy_search(pair[0]) @@ -2159,6 +2171,7 @@ async def start_league_day(channel, league, partial = False): home.set_pitcher(rotation_slot=league.day) this_game = games.game(away.finalize(), home.finalize(), length = game_length) + this_game.weather = league.get_weather_now(home.name)(this_game) this_game, state_init = prepare_game(this_game) state_init["is_league"] = True @@ -2174,6 +2187,11 @@ async def start_league_day(channel, league, partial = False): main_controller.master_games_dic[id] = (this_game, state_init, discrim_string) ext = "?league=" + urllib.parse.quote_plus(league.name) + + if weather_check_result == 2: + await channel.send(f"The entire league is struck by a {league.weather_override.emoji} {league.weather_override.name}! The games must go on.") + elif weather_check_result == 1: + await channel.send(f"The {league.weather_override.emoji} {league.weather_override.name} continues to afflict the league.") if league.last_series_check(): #if finals await channel.send(f"The final series of the {league.name} regular season is starting now, at {config()['simmadome_url']+ext}") @@ -2274,6 +2292,11 @@ async def league_day_watcher(channel, league, games_list, filter_url, last = Fal leagues.save_league(league) active_standings[league] = await channel.send(embed=league.standings_embed()) await channel.send(f"The day {league.day} games for the {league.name} will start in {math.ceil(wait_seconds/60)} minutes.") + weather_check_result = league.weather_event_check() + if weather_check_result == 2: + await channel.send(f"The entire league is struck by a {league.weather_override.emoji} {league.weather_override.name}! The games must go on.") + elif weather_check_result == 1: + await channel.send(f"The {league.weather_override.emoji} {league.weather_override.name} continues to afflict the league.") await asyncio.sleep(wait_seconds) await channel.send(f"A {league.name} series is continuing now at {filter_url}") games_list = await continue_league_series(league, queued_games, games_list, series_results, missed) @@ -2361,6 +2384,7 @@ async def continue_league_series(league, queue, games_list, series_results, miss home_team = games.get_team(oldgame.teams["home"].name) home_team.set_pitcher(rotation_slot=league.day) this_game = games.game(away_team.finalize(), home_team.finalize(), length = league.game_length) + this_game.weather = league.get_weather_now(home_team.name)(this_game) this_game, state_init = prepare_game(this_game) state_init["is_league"] = True @@ -2454,6 +2478,4 @@ async def league_postseason(channel, league): season_save(league) league.season_reset() - - -client.run(config()["token"]) +client.run(config()["token"]) \ No newline at end of file diff --git a/weather.py b/weather.py index 8f0e8b2..7c28fbb 100644 --- a/weather.py +++ b/weather.py @@ -1,15 +1,20 @@ -import random -import math +import random, math, roman from gametext import appearance_outcomes, base_string class Weather: + name = "Sunny" + emoji = "🌞" + duration_range = [3,5] + def __init__(self, game): - self.name = "Sunny" - self.emoji = "🌞" + pass def __str__(self): return f"{self.emoji} {self.name}" + def set_duration(self): + pass + def modify_atbat_stats(self, player_rolls): # Activates before batting pass @@ -37,27 +42,33 @@ class Weather: def modify_atbat_message(self, game, state): pass + def modify_gamestate(self, game, state): + pass + + def modify_game_end_message(self, game, state): + pass + class Supernova(Weather): - def __init__(self, game): - self.name = "Supernova" - self.emoji = "🌟" + name = "Supernova" + emoji = "🌟" + duration_range = [1,2] def modify_atbat_stats(self, roll): roll["pitch_stat"] *= 0.8 class Midnight(Weather): - def __init__(self, game): - self.name = "Midnight" - self.emoji = "🕶" + name = "Midnight" + emoji = "🕶" + duration_range = [1,1] def modify_steal_stats(self, roll): roll["run_stars"] *= 2 class SlightTailwind(Weather): - def __init__(self, game): - self.name = "Slight Tailwind" - self.emoji = "🏌️‍♀️" + name = "Slight Tailwind" + emoji = "🏌️‍♀️" + duration_range = [1,2] def activate(self, game, result): @@ -73,9 +84,9 @@ class SlightTailwind(Weather): }) class Starlight(Weather): - def __init__(self, game): - self.name = "Starlight" - self.emoji = "🌃" + name = "Starlight" + emoji = "🌃" + duration_range = [2,2] def activate(self, game, result): @@ -104,10 +115,12 @@ class Starlight(Weather): state["update_text"] = f"The stars enjoy watching dragons play baseball, and allow {result['batter']} to hit a dinger! {game.last_update[1]} runs scored!" -class HeavySnow(Weather): +class Blizzard(Weather): + name = "Blizzard" + emoji = "❄" + duration_range = [2,3] + def __init__(self, game): - self.name = "Heavy Snow" - self.emoji = "❄" self.counter_away = random.randint(0,len(game.teams['away'].lineup)-1) self.counter_home = random.randint(0,len(game.teams['home'].lineup)-1) @@ -150,9 +163,9 @@ class HeavySnow(Weather): game.current_batter = bat_team.pitcher class Twilight(Weather): - def __init__(self,game): - self.name = "Twilight" - self.emoji = "👻" + name = "Twilight" + emoji = "👻" + duration_range = [2,3] def modify_atbat_roll(self, outcome, roll, defender): error_line = - (math.log(defender.stlats["defense_stars"] + 1)/50) + 1 @@ -171,9 +184,9 @@ class Twilight(Weather): state["update_text"] += f" {this_game.last_update[1]} runs scored!" class ThinnedVeil(Weather): - def __init__(self,game): - self.name = "Thinned Veil" - self.emoji = "🌌" + name = "Thinned Veil" + emoji = "🌌" + duration_range = [1,3] def activate(self, game, result): if result["ishit"]: @@ -186,10 +199,11 @@ class ThinnedVeil(Weather): state["update_text"] += f" {game.last_update[0]['batter']}'s will manifests on {base_string(game.last_update[1])} base." class HeatWave(Weather): - def __init__(self,game): - self.name = "Heat Wave" - self.emoji = "🌄" + name = "Heat Wave" + emoji = "🌄" + duration_range = [2,3] + def __init__(self,game): self.counter_away = random.randint(2,4) self.counter_home = random.randint(2,4) @@ -228,9 +242,9 @@ class HeatWave(Weather): class Drizzle(Weather): - def __init__(self,game): - self.name = "Drizzle" - self.emoji = "🌧" + name = "Drizzle" + emoji = "🌧" + duration_range = [2,3] def on_flip_inning(self, game): if game.top_of_inning: @@ -253,9 +267,11 @@ class Drizzle(Weather): state["update_text"] += f' Due to inclement weather, {placed_player.name} is placed on second base.' class Breezy(Weather): - def __init__(self, game): - self.name = "Breezy" - self.emoji = "🎐" + name = "Breezy" + emoji = "🎐" + duration_range = [1,3] + + def __init__(self, game): self.activation_chance = 0.08 def activate(self, game, result): @@ -295,9 +311,11 @@ class Breezy(Weather): }) class MeteorShower(Weather): + name = "Meteor Shower" + emoji = "🌠" + duration_range = [1,3] + def __init__(self, game): - self.name = "Meteor Shower" - self.emoji = "🌠" self.activation_chance = 0.13 def activate(self, game, result): @@ -318,22 +336,163 @@ class MeteorShower(Weather): "text_only": True, "weather_message": True }) + +class Hurricane(Weather): + name = "Hurricane" + emoji = "🌀" + duration_range = [1,1] + + def __init__(self, game): + self.swaplength = random.randint(2,4) + self.swapped = False + + def on_flip_inning(self, game): + if game.top_of_inning and (game.inning % self.swaplength) == 0: + self.swaplength = random.randint(2,4) + self.swapped = True + + def modify_top_of_inning_message(self, game, state): + if self.swapped: + game.teams["home"].score, game.teams["away"].score = (game.teams["away"].score, game.teams["home"].score) #swap scores + state["away_score"], state["home_score"] = (game.teams["away"].score, game.teams["home"].score) + state["update_emoji"] = self.emoji + state["update_text"] += " The hurricane rages on, flipping the scoreboard!" + self.swapped = False + +class Tornado(Weather): + name = "Tornado" + emoji = "🌪" + duration_range = [1,2] + + def __init__(self, game): + self.activation_chance = 0.33 + self.counter = 0 + + def activate(self, game, result): + if self.counter == 0 and random.random() < self.activation_chance and game.occupied_bases() != {}: + runners = list(game.bases.values()) + current_runners = runners.copy() + self.counter = 5 + while runners == current_runners and self.counter > 0: + random.shuffle(runners) + self.counter -= 1 + for index in range(1,4): + game.bases[index] = runners[index-1] + + result.clear() + result.update({ + "text": f"The tornado sweeps across the field and pushes {'the runners' if len(game.occupied_bases().values())>1 else list(game.occupied_bases().values())[0].name} to a different base!", + "text_only": True, + "weather_message": True + }) + self.counter = 2 + + elif self.counter > 0: + self.counter -= 1 +class Downpour(Weather): + name = "Torrential Downpour" + emoji = '⛈' + duration_range = [1,1] + + def __init__(self, game): + self.target = game.max_innings + self.name = f"Torrential Downpour: {roman.roman_convert(str(self.target))}" + self.emoji = '⛈' + + + def on_flip_inning(self, game): + high_score = game.teams["home"].score if game.teams["home"].score > game.teams["away"].score else game.teams["away"].score + if high_score >= self.target and game.teams["home"].score != game.teams["away"].score: + game.max_innings = game.inning + else: + game.max_innings = game.inning + 1 + + def modify_gamestate(self, game, state): + state["max_innings"] = "∞" + + def modify_top_of_inning_message(self, game, state): + state["update_emoji"] = self.emoji + state["update_text"] = "The gods are not yet pleased. Play continues through the storm." + + def modify_game_end_message(self, game, state): + state["update_emoji"] = self.emoji + state["update_text"] = f"{self.target} runs are reached, pleasing the gods. The storm clears." + + def all_weathers(): weathers_dic = { "Supernova" : Supernova, "Midnight": Midnight, "Slight Tailwind": SlightTailwind, - "Heavy Snow": HeavySnow, + "Blizzard": Blizzard, "Twilight" : Twilight, "Thinned Veil" : ThinnedVeil, "Heat Wave" : HeatWave, "Drizzle" : Drizzle, "Breezy": Breezy, "Starlight" : Starlight, - "Meteor Shower" : MeteorShower + "Meteor Shower" : MeteorShower, + "Hurricane" : Hurricane, + "Tornado" : Tornado, + "Torrential Downpour" : Downpour } return weathers_dic +class WeatherChains(): + light = [SlightTailwind, Twilight, Breezy, Drizzle] #basic starting points for weather, good comfortable spots to return to + 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 + disaster = [Hurricane, Tornado, Downpour, Blizzard] #storms + aftermath = [Midnight, Starlight, MeteorShower] #calm epilogues + + dictionary = { + #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]), + SlightTailwind : ([Breezy, Drizzle, Tornado], [3,3,1]), + Blizzard : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]), + Twilight : ([ThinnedVeil, Midnight, MeteorShower, SlightTailwind], [2,4,2,1]), + ThinnedVeil : (light, None), + HeatWave : ([Tornado, Hurricane, SlightTailwind, Breezy],[4,4,1,1]), + Drizzle : ([Hurricane, Downpour, Blizzard],[2,2,1]), + Breezy : ([Drizzle, HeatWave, Blizzard, Tornado], [3,3,1,1]), + Starlight : ([SlightTailwind, Twilight, Breezy, Drizzle, ThinnedVeil, HeatWave], None), + MeteorShower : ([Starlight, ThinnedVeil, HeatWave], None), + Hurricane : ([Midnight, Starlight, MeteorShower, Twilight, Downpour], [2,2,2,2,4]), + Tornado : ([Midnight, Starlight, MeteorShower, Twilight, Downpour],[2,2,2,2,4]), + Downpour : (aftermath, None) + } + + chains = [ + [Hurricane, Drizzle, Hurricane] + ] + + def chain_weather(weather_instance): + #weather_type = type(weather_instance) + weather_type = weather_instance + options, weight = WeatherChains.dictionary[weather_type] + return random.choices(options, weights = weight)[0] + + def parent_weathers(weather_type): + parents = [] + for this_weather, (children, _) in WeatherChains.dictionary.items(): + if weather_type in children: + parents.append(this_weather) + return parents + + def starting_weather(): + return random.choice(WeatherChains.light + WeatherChains.magic) + + def debug_weathers(): + names = ["a.txt", "b.txt", "c.txt"] + for name in names: + current = random.choice(list(all_weathers().values())) + out = "" + for i in range(0,50): + out += f"{current.name} {current.emoji}\n" + current = WeatherChains.chain_weather(current) + + with open("data/"+name, "w", encoding='utf-8') as file: + file.write(out) \ No newline at end of file