Merge pull request #219 from Sakimori/the-storm
Finish brewing the storm
This commit is contained in:
commit
fd63a2381a
|
@ -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!
|
||||
|
||||
|
|
23
database.py
23
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
|
||||
|
|
8
games.py
8
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):
|
||||
|
|
|
@ -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)
|
||||
|
|
72
leagues.py
72
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
|
|
@ -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!"
|
||||
|
|
|
@ -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"])
|
235
weather.py
235
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)
|
Loading…
Reference in a new issue