Merge remote-tracking branch 'upstream/indev' into leagues
This commit is contained in:
commit
b713de220e
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
venv/
|
||||
matteo_env/
|
||||
__pycache__/
|
||||
simmadome/node_modules
|
||||
data/
|
||||
.git/
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -344,6 +344,7 @@ config.json
|
|||
games_config.json
|
||||
weather_config.json
|
||||
ids
|
||||
data/
|
||||
|
||||
# database
|
||||
matteo.db
|
||||
|
@ -351,5 +352,8 @@ matteo.db-wal
|
|||
matteo.db-shm
|
||||
/data/leagues/*
|
||||
/matteo_env/Lib/site-packages/flask_socketio/__init__.py
|
||||
Pipfile
|
||||
|
||||
env
|
||||
/data/leagues
|
||||
/simmadome/build
|
||||
|
|
19
Dockerfile
19
Dockerfile
|
@ -1,9 +1,20 @@
|
|||
FROM python:3.8
|
||||
EXPOSE 5000
|
||||
|
||||
# - Build stage 1: frontend (simmadome/ directory)
|
||||
FROM node:alpine AS frontend
|
||||
WORKDIR /app
|
||||
|
||||
COPY . ./
|
||||
COPY simmadome/package.json simmadome/package-lock.json ./
|
||||
RUN npm install
|
||||
COPY simmadome/ ./
|
||||
RUN npm run build
|
||||
|
||||
# - Build stage 2: backend (Python)
|
||||
FROM python:3.8
|
||||
EXPOSE 5000
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
COPY . ./
|
||||
COPY --from=frontend /app/build/ simmadome/build/
|
||||
|
||||
CMD ["python", "the_prestige.py"]
|
||||
|
|
1111
LICENSE.md
1111
LICENSE.md
File diff suppressed because it is too large
Load Diff
56
README.md
56
README.md
|
@ -3,7 +3,7 @@
|
|||
|
||||
blaseball, blaseball, is back! in an unofficial capacity. this project is completely unaffiliated with the game band.
|
||||
|
||||
we have custom players (generated by onomancer), custom teams, custom leagues (that last one is coming soon™), all set up in discord and watchable at https://simsim.sibr.dev!
|
||||
we have custom players (generated by onomancer), custom teams, custom leagues, all set up in discord and watchable at https://simsim.sibr.dev!
|
||||
|
||||
if you would like to add matteo to your server to be able to set up teams and games, you can do so with this link: https://discord.com/api/oauth2/authorize?client_id=789956166796574740&permissions=388160&scope=bot
|
||||
|
||||
|
@ -12,7 +12,6 @@ accepting pull requests, check the issues for to-dos.
|
|||
|
||||
## commands: (everything here is case sensitive, and can be prefixed with either m; or m!)
|
||||
### team commands:
|
||||
|
||||
#### creation and deletion:
|
||||
- m;saveteam
|
||||
- saves a team to the database allowing it to be used for games. use this command at the top of a list with entries separated by new lines:
|
||||
|
@ -27,7 +26,6 @@ accepting pull requests, check the issues for to-dos.
|
|||
- allows you to delete the team with the provided name. you'll get an embed with a confirmation to prevent accidental deletions. hit the 👍 and your team will be deleted.
|
||||
- m;import
|
||||
- imports an onomancer collection as a new team. you can use the new onomancer simsim setting to ensure compatibility. similarly to saveteam, you'll get a team embed with a prompt to confirm, hit the 👍 and your team will be saved!
|
||||
|
||||
#### editing (all of these commands require ownership and exact spelling of the team name):
|
||||
- m;addplayer batter/pitcher [team name] \[player name]
|
||||
- adds a new player to the end of your team, either in the lineup or the rotation depending on which version you use. use addplayer batter or addplayer pitcher at the top of a list with entries separated by new lines:
|
||||
|
@ -46,7 +44,6 @@ accepting pull requests, check the issues for to-dos.
|
|||
- removes a player from your team. if there are multiple copies of the same player on a team this will only delete the first one. use this command at the top of a list with entries separated by new lines:
|
||||
- the name of the team you want to remove the player from.
|
||||
- the name of the player you want to remove.
|
||||
|
||||
#### viewing and searching:
|
||||
- m;showteam [name]
|
||||
- shows the lineup, rotation, and slogan of any saved team in a discord embed with primary stat star ratings for all of the players. this command has fuzzy search so you don't need to type the full name of the team as long as you give enough to identify the team you're looking for.
|
||||
|
@ -55,14 +52,6 @@ accepting pull requests, check the issues for to-dos.
|
|||
- m;showallteams
|
||||
- shows a paginated list of all teams available for games which can be scrolled through.
|
||||
|
||||
### player commands:
|
||||
- m;showplayer [name]
|
||||
- displays any name's stars, there's a limit of 70 characters. that should be *plenty*. note: if you want to lookup a lot of different players you can do it on onomancer instead of spamming this command a bunch and clogging up discord: https://onomancer.sibr.dev/reflect
|
||||
- m;idolize [name]
|
||||
- records any name as your idol, mostly for fun.
|
||||
- m;showidol
|
||||
- displays your idol's name and stars in a discord embed.
|
||||
|
||||
### game commands:
|
||||
- m;startgame --day # or -d #
|
||||
- starts a game with premade teams made using saveteam. provides a link to the website where you can watch the game.
|
||||
|
@ -81,6 +70,49 @@ accepting pull requests, check the issues for to-dos.
|
|||
- the name of the tournament.
|
||||
- the name of each participating team on its own line.
|
||||
|
||||
### draft commands
|
||||
- m;startdraft
|
||||
- starts a draft with an arbitrary number of participants. use this command at the top of a list with entries separated by new lines:
|
||||
- for each participant's entry you need three lines:
|
||||
- their discord @
|
||||
- their team name
|
||||
- their team slogan
|
||||
- post this with all three of these things for all participants and the draft will begin.
|
||||
- the draft will begin once all participants have given a 👍 and will proceed in the order that participants were entered. each participant will select 12 hitters and 1 pitcher from a pool of 20 random players which will refresh automatically when it becomes small.
|
||||
- m;draft [name]
|
||||
- use this on your turn during a draft to pick your player.
|
||||
- you can also just use a 'd' instead of the full command.
|
||||
|
||||
### league commands
|
||||
- all of these commands are for leagues that have already been started. to start a league, click the 'create a league' button on the website and fill out the info for your league there, then use the m;claimleague command in discord to set yourself as the owner.
|
||||
- commissioner commands (all of these except for m;claimleague require ownership of the specified league):
|
||||
- m;claimleague [leaguename]
|
||||
- sets yourself as the owner of an unclaimed league created on the website. make sure to do this as soon as possible since if someone does this before you, you will not have access to the league.
|
||||
- m;addleagueowner [leaguename]
|
||||
- use this command at the top of a list of @mentions, with entries separated by new lines, of people you want to have owner powers in your league.
|
||||
- m;startleague [leaguename] --queue #/-q # --noautopostseason
|
||||
- send this command with the number of games per hour you want on the next line, minimum 1 (one game every hour), maximum 12 (one game every 5 minutes, uses spillover rules).
|
||||
- starts the playing of league games at the pace specified, by default will play the entire season and the postseason unless an owner pauses the league with the m;pauseleague command.
|
||||
- if you use the --queue #/-q # flag, the league will only play # series' at a time before automatically pausing until you use this command again.
|
||||
- if you use the --noautopostseason flag, instead of starting automatically, the league will pause at the end of the regular season and not start the postseason until you use this command again.
|
||||
- m;pauseleague [leaguename]
|
||||
- pauses the specified league after the current series finishes until the league is started again with m;startleague.
|
||||
- general commands (all of these can be used by anyone):
|
||||
- m;leaguestandings [leaguename]
|
||||
- displays the current standings for the specified league.
|
||||
- m;leaguewildcard [leaguename]
|
||||
- displays the wild card standings for the specified league. if the league doesn't have wild cards, it will instead tell you that.
|
||||
- m;leagueschedule [leaguename]
|
||||
- displays the upcoming schedule for the specified league. shows the current series and the next three series after that for every team.
|
||||
|
||||
### player commands:
|
||||
- m;showplayer [name]
|
||||
- displays any name's stars, there's a limit of 70 characters. that should be *plenty*. note: if you want to lookup a lot of different players you can do it on onomancer instead of spamming this command a bunch and clogging up discord: https://onomancer.sibr.dev/reflect
|
||||
- m;idolize [name]
|
||||
- records any name as your idol, mostly for fun.
|
||||
- m;showidol
|
||||
- displays your idol's name and stars in a discord embed.
|
||||
|
||||
### other commands:
|
||||
- m;help [command]
|
||||
- shows instructions for a given command. if no command is provided, it will instead provide a list of all of the commands that instructions can be provided for.
|
||||
|
|
25
games.py
25
games.py
|
@ -31,13 +31,14 @@ def config():
|
|||
def all_weathers():
|
||||
weathers_dic = {
|
||||
#"Supernova" : weather("Supernova", "🌟"),
|
||||
"Midnight": weather("Midnight", "🕶"),
|
||||
#"Midnight": weather("Midnight", "🕶"),
|
||||
"Slight Tailwind": weather("Slight Tailwind", "🏌️♀️"),
|
||||
"Heavy Snow": weather("Heavy Snow", "❄")
|
||||
"Heavy Snow": weather("Heavy Snow", "❄"),
|
||||
"Twilight" : weather("Twilight", "👻"),
|
||||
"Thinned Veil" : weather("Thinned Veil", "🌌")
|
||||
}
|
||||
return weathers_dic
|
||||
|
||||
|
||||
class appearance_outcomes(Enum):
|
||||
strikeoutlooking = "strikes out looking."
|
||||
strikeoutswinging = "strikes out swinging."
|
||||
|
@ -269,6 +270,13 @@ class game(object):
|
|||
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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
if pb_system_stat <= 0:
|
||||
|
@ -313,7 +321,7 @@ class game(object):
|
|||
outcome["ishit"] = True
|
||||
if hitnum < 1:
|
||||
outcome["text"] = appearance_outcomes.single
|
||||
elif hitnum < 2.85:
|
||||
elif hitnum < 2.85 or "error" in outcome.keys():
|
||||
outcome["text"] = appearance_outcomes.double
|
||||
elif hitnum < 3.1:
|
||||
outcome["text"] = appearance_outcomes.triple
|
||||
|
@ -384,6 +392,11 @@ class game(object):
|
|||
if base is not None:
|
||||
runs += 1
|
||||
self.bases = {1 : None, 2 : None, 3 : None}
|
||||
if "veil" in outcome.keys():
|
||||
if runs < 4:
|
||||
self.bases[runs] = self.get_batter()
|
||||
else:
|
||||
runs += 1
|
||||
return runs
|
||||
|
||||
elif "advance" in outcome.keys():
|
||||
|
@ -535,6 +548,10 @@ class game(object):
|
|||
elif result["text"] == appearance_outcomes.homerun or result["text"] == appearance_outcomes.grandslam:
|
||||
self.get_batter().game_stats["total_bases"] += 4
|
||||
self.get_batter().game_stats["home_runs"] += 1
|
||||
if self.weather.name == "Thinned Veil":
|
||||
result["veil"] = True
|
||||
|
||||
|
||||
|
||||
scores_to_add += self.baserunner_check(defender, result)
|
||||
|
||||
|
|
|
@ -21,6 +21,23 @@ def create_connection(league_name):
|
|||
print("oops, db connection no work")
|
||||
return conn
|
||||
|
||||
def create_season_connection(league_name, season_num):
|
||||
#create connection, create db if doesn't exist
|
||||
conn = None
|
||||
try:
|
||||
if not os.path.exists(os.path.join(data_dir, league_dir, league_name)):
|
||||
|
||||
os.makedirs(os.path.join(data_dir, league_dir, league_name))
|
||||
conn = sql.connect(os.path.join(data_dir, league_dir, league_name, season_num, f"{league_name}.db"))
|
||||
|
||||
# enable write-ahead log for performance and resilience
|
||||
conn.execute('pragma journal_mode=wal')
|
||||
|
||||
return conn
|
||||
except:
|
||||
print("oops, db connection no work")
|
||||
return conn
|
||||
|
||||
def state(league_name):
|
||||
if not os.path.exists(os.path.dirname(os.path.join(data_dir, league_dir, league_name, f"{league_name}.state"))):
|
||||
os.makedirs(os.path.dirname(os.path.join(data_dir, league_dir, league_name, f"{league_name}.state")))
|
||||
|
@ -73,33 +90,22 @@ def init_league_db(league):
|
|||
for pitcher in team.rotation:
|
||||
c.execute(player_string, (pitcher.name, team.name))
|
||||
|
||||
state_dic = {
|
||||
"day" : league.day,
|
||||
"schedule" : league.schedule,
|
||||
"game_length" : league.game_length,
|
||||
"series_length" : league.series_length,
|
||||
"games_per_hour" : league.games_per_hour,
|
||||
"owner" : None,
|
||||
"historic" : False
|
||||
}
|
||||
if not os.path.exists(os.path.dirname(os.path.join(data_dir, league_dir, league.name, f"{league.name}.state"))):
|
||||
os.makedirs(os.path.dirname(os.path.join(data_dir, league_dir, league.name, f"{league.name}.state")))
|
||||
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)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def save_league(league):
|
||||
if league_exists(league.name):
|
||||
state_dic = {
|
||||
"season" : league.season,
|
||||
"day" : league.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,
|
||||
"historic" : league.historic
|
||||
"champion" : league.champion,
|
||||
"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)
|
||||
|
@ -149,11 +155,49 @@ def get_standings(league_name):
|
|||
conn.close()
|
||||
return standings_array
|
||||
|
||||
def season_save(league):
|
||||
if league_exists(league.name):
|
||||
seasons = 1
|
||||
with os.scandir(os.path.join(data_dir, league_dir, league.name)) as folder:
|
||||
for item in folder:
|
||||
if "." not in item.name:
|
||||
seasons += 1
|
||||
new_dir = os.path.join(data_dir, league_dir, league.name, str(seasons))
|
||||
os.makedirs(new_dir)
|
||||
with os.scandir(os.path.join(data_dir, league_dir, league.name)) as folder:
|
||||
for item in folder:
|
||||
if "." in item.name:
|
||||
os.rename(os.path.join(data_dir, league_dir, league.name, item.name), os.path.join(new_dir, item.name))
|
||||
|
||||
def get_past_standings(league_name, season_num):
|
||||
if league_exists(league_name):
|
||||
with os.scandir(os.path.join(data_dir, league_dir, league_name)) as folder:
|
||||
for item in folder:
|
||||
if item.name == str(season_num):
|
||||
conn = create_season_connection(league_name, str(item.name))
|
||||
if conn is not None:
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute("SELECT name, wins, losses, run_diff FROM teams",)
|
||||
standings_array = c.fetchall()
|
||||
conn.close()
|
||||
return standings_array
|
||||
|
||||
def get_past_champion(league_name, season_num):
|
||||
if league_exists(league_name):
|
||||
with os.scandir(os.path.join(data_dir, league_dir, league_name)) as folder:
|
||||
for item in folder:
|
||||
if item.name == str(season_num):
|
||||
with open(os.path.join(data_dir, league_dir, league_name, item.name, f"{league_name}.state")) as state_file:
|
||||
state_dic = json.load(state_file)
|
||||
return state_dic["champion"]
|
||||
|
||||
def league_exists(league_name):
|
||||
with os.scandir(os.path.join(data_dir, league_dir)) as folder:
|
||||
for subfolder in folder:
|
||||
if league_name in subfolder.name:
|
||||
return not state(league_name)["historic"]
|
||||
if league_name == subfolder.name:
|
||||
with os.scandir(subfolder.path) as league_folder:
|
||||
for item in league_folder:
|
||||
if item.name == f"{league_name}.db":
|
||||
return True
|
||||
return False
|
203
leagues.py
203
leagues.py
|
@ -12,13 +12,18 @@ class league_structure(object):
|
|||
self.name = name
|
||||
self.historic = False
|
||||
self.owner = None
|
||||
self.season = 1
|
||||
self.autoplay = -1
|
||||
self.champion = None
|
||||
|
||||
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.constraints = {
|
||||
"division_games" : division_games,
|
||||
"inter_div_games" : inter_division_games,
|
||||
"inter_league_games" : inter_league_games
|
||||
"inter_league_games" : inter_league_games,
|
||||
"division_leaders" : 0,
|
||||
"wild_cards" : 0
|
||||
}
|
||||
self.day = 1
|
||||
self.schedule = {}
|
||||
|
@ -27,6 +32,14 @@ class league_structure(object):
|
|||
self.active = False
|
||||
self.games_per_hour = games_per_hour
|
||||
|
||||
def season_reset(self):
|
||||
self.season += 1
|
||||
self.day = 1
|
||||
self.champion = None
|
||||
self.schedule = {}
|
||||
self.generate_schedule()
|
||||
save_league(self)
|
||||
|
||||
def add_stats_from_game(self, players_dic):
|
||||
league_db.add_stats(self.name, players_dic)
|
||||
|
||||
|
@ -40,6 +53,41 @@ class league_structure(object):
|
|||
def day_to_series_num(self, day):
|
||||
return math.ceil((self.day)/self.series_length)
|
||||
|
||||
def tiebreaker_required(self):
|
||||
standings = {}
|
||||
matchups = []
|
||||
tournaments = []
|
||||
for team_name, wins, losses, run_diff in league_db.get_standings(self.name):
|
||||
standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff}
|
||||
|
||||
for subleague in iter(self.league.keys()):
|
||||
team_dic = {}
|
||||
subleague_array = []
|
||||
wildcard_leaders = []
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
division_standings = []
|
||||
division_standings += self.division_standings(self.league[subleague][division], standings)
|
||||
division_leaders = division_standings[:self.constraints["division_leaders"]]
|
||||
for division_team, wins, losses, diff, gb in division_standings[self.constraints["division_leaders"]:]:
|
||||
if division_team.name != division_leaders[-1][0].name and standings[division_team.name]["wins"] == standings[division_leaders[-1][0].name]["wins"]:
|
||||
matchups.append((division_team, division_standings[self.constraints["division_leaders"]-1][0], f"{division} Tiebreaker"))
|
||||
|
||||
this_div_wildcard = [this_team for this_team, wins, losses, diff, gb in self.division_standings(self.league[subleague][division], standings)[self.constraints["division_leaders"]:]]
|
||||
subleague_array += this_div_wildcard
|
||||
if self.constraints["wild_cards"] > 0:
|
||||
wildcard_standings = self.division_standings(subleague_array, standings)
|
||||
wildcard_leaders = wildcard_standings[:self.constraints["wild_cards"]]
|
||||
for wildcard_team, wins, losses, diff, gb in wildcard_standings[self.constraints["wild_cards"]:]:
|
||||
if wildcard_team.name != wildcard_leaders[-1][0].name and standings[wildcard_team.name]["wins"] == standings[wildcard_leaders[-1][0].name]["wins"]:
|
||||
matchups.append((wildcard_team, wildcard_standings[self.constraints["wild_cards"]-1][0], f"{subleague} Wildcard Tiebreaker"))
|
||||
|
||||
for team_a, team_b, type in matchups:
|
||||
tourney = tournament(f"{self.name} {type}",{team_a : {"wins" : 1}, team_b : {"wins" : 0}}, finals_series_length=1, secs_between_games=int(3600/self.games_per_hour), secs_between_rounds=int(7200/self.games_per_hour))
|
||||
tourney.build_bracket(by_wins = True)
|
||||
tourney.league = self
|
||||
tournaments.append(tourney)
|
||||
return tournaments
|
||||
|
||||
def find_team(self, team_name):
|
||||
for subleague in iter(self.league.keys()):
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
|
@ -179,30 +227,144 @@ class league_structure(object):
|
|||
scheduled = True
|
||||
day += 1
|
||||
|
||||
def standings_embed(self):
|
||||
def division_standings(self, division, standings):
|
||||
def sorter(team_in_list):
|
||||
if team_in_list[2] == 0 and team_in_list[1] == 0:
|
||||
return (0, team_in_list[3])
|
||||
return (team_in_list[1]/(team_in_list[1]+team_in_list[2]), team_in_list[3])
|
||||
|
||||
teams = division.copy()
|
||||
|
||||
for index in range(0, len(teams)):
|
||||
this_team = teams[index]
|
||||
teams[index] = [this_team, standings[teams[index].name]["wins"], standings[teams[index].name]["losses"], standings[teams[index].name]["run_diff"], 0]
|
||||
|
||||
teams.sort(key=sorter, reverse=True)
|
||||
return teams
|
||||
|
||||
def past_standings(self, season_num):
|
||||
this_embed = Embed(color=Color.purple(), title=self.name)
|
||||
standings = {}
|
||||
for team_name, wins, losses, run_diff in league_db.get_past_standings(self.name, season_num):
|
||||
standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff}
|
||||
|
||||
this_embed.add_field(name=league_db.get_past_champion(self.name, season_num), value=f"Season {season_num} champions", inline = False)
|
||||
|
||||
for subleague in iter(self.league.keys()):
|
||||
this_embed.add_field(name="Subleague:", value=f"**{subleague}**", inline = False)
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
teams = self.division_standings(self.league[subleague][division], standings)
|
||||
|
||||
for index in range(0, len(teams)):
|
||||
if index == self.constraints["division_leaders"] - 1:
|
||||
teams[index][4] = "-"
|
||||
else:
|
||||
games_behind = ((teams[self.constraints["division_leaders"] - 1][1] - teams[index][1]) + (teams[index][2] - teams[self.constraints["division_leaders"] - 1][2]))/2
|
||||
teams[index][4] = games_behind
|
||||
teams_string = ""
|
||||
for this_team in teams:
|
||||
if this_team[2] != 0 or this_team[1] != 0:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: {round(this_team[1]/(this_team[1]+this_team[2]), 3)} GB: {this_team[4]}\n\n"
|
||||
else:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: - GB: {this_team[4]}\n\n"
|
||||
|
||||
this_embed.add_field(name=f"{division} Division:", value=teams_string, inline = False)
|
||||
|
||||
this_embed.set_footer(text=f"Season {season_num} Final Standings")
|
||||
return this_embed
|
||||
|
||||
def season_length(self):
|
||||
return int(list(self.schedule.keys())[-1]) * self.series_length
|
||||
|
||||
def standings_embed(self):
|
||||
this_embed = Embed(color=Color.purple(), title=f"{self.name} Season {self.season}")
|
||||
standings = {}
|
||||
for team_name, wins, losses, run_diff in league_db.get_standings(self.name):
|
||||
standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff}
|
||||
for subleague in iter(self.league.keys()):
|
||||
this_embed.add_field(name="Subleague:", value=f"**{subleague}**", inline = False)
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
this_embed.add_field(name="Division:", value=f"**{division}**", inline = False)
|
||||
teams = self.league[subleague][division].copy()
|
||||
teams = self.division_standings(self.league[subleague][division], standings)
|
||||
|
||||
for index in range(0, len(teams)):
|
||||
this_team = teams[index]
|
||||
teams[index] = (this_team, standings[teams[index].name]["wins"], standings[teams[index].name]["losses"], standings[teams[index].name]["run_diff"],)
|
||||
|
||||
def sorter(team_in_list):
|
||||
return (team_in_list[1], team_in_list[3])
|
||||
teams.sort(key=sorter, reverse=True)
|
||||
|
||||
if index == self.constraints["division_leaders"] - 1:
|
||||
teams[index][4] = "-"
|
||||
else:
|
||||
games_behind = ((teams[self.constraints["division_leaders"] - 1][1] - teams[index][1]) + (teams[index][2] - teams[self.constraints["division_leaders"] - 1][2]))/2
|
||||
teams[index][4] = games_behind
|
||||
teams_string = ""
|
||||
for this_team in teams:
|
||||
this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} Diff: {this_team[3]}", inline = False)
|
||||
if this_team[2] != 0 or this_team[1] != 0:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: {round(this_team[1]/(this_team[1]+this_team[2]), 3)} GB: {this_team[4]}\n\n"
|
||||
else:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: - GB: {this_team[4]}\n\n"
|
||||
|
||||
this_embed.set_footer(text=f"Standings as of day {self.day-1}")
|
||||
this_embed.add_field(name=f"{division} Division:", value=teams_string, inline = False)
|
||||
|
||||
this_embed.set_footer(text=f"Standings as of day {self.day-1} / {self.season_length()}")
|
||||
return this_embed
|
||||
|
||||
def wildcard_embed(self):
|
||||
this_embed = Embed(color=Color.purple(), title=f"{self.name} Wildcard Race")
|
||||
standings = {}
|
||||
for team_name, wins, losses, run_diff in league_db.get_standings(self.name):
|
||||
standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff}
|
||||
for subleague in iter(self.league.keys()):
|
||||
subleague_array = []
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
this_div = [this_team for this_team, wins, losses, diff, gb in self.division_standings(self.league[subleague][division], standings)[self.constraints["division_leaders"]:]]
|
||||
subleague_array += this_div
|
||||
|
||||
teams = self.division_standings(subleague_array, standings)
|
||||
teams_string = ""
|
||||
for index in range(0, len(teams)):
|
||||
if index == self.constraints["wild_cards"] - 1:
|
||||
teams[index][4] = "-"
|
||||
else:
|
||||
games_behind = ((teams[self.constraints["wild_cards"] - 1][1] - teams[index][1]) + (teams[index][2] - teams[self.constraints["wild_cards"] - 1][2]))/2
|
||||
teams[index][4] = games_behind
|
||||
|
||||
for this_team in teams:
|
||||
if this_team[2] != 0 or this_team[1] != 0:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: {round(this_team[1]/(this_team[1]+this_team[2]), 3)} GB: {this_team[4]}\n\n"
|
||||
else:
|
||||
teams_string += f"**{this_team[0].name}\n**{this_team[1]} - {this_team[2]} WR: - GB: {this_team[4]}\n\n"
|
||||
|
||||
this_embed.add_field(name=f"{subleague} League:", value=teams_string, inline = False)
|
||||
|
||||
this_embed.set_footer(text=f"Wildcard standings as of day {self.day-1}")
|
||||
return this_embed
|
||||
|
||||
def champ_series(self):
|
||||
tournaments = []
|
||||
standings = {}
|
||||
|
||||
for team_name, wins, losses, run_diff in league_db.get_standings(self.name):
|
||||
standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff}
|
||||
|
||||
for subleague in iter(self.league.keys()):
|
||||
team_dic = {}
|
||||
division_leaders = []
|
||||
subleague_array = []
|
||||
wildcard_leaders = []
|
||||
for division in iter(self.league[subleague].keys()):
|
||||
division_leaders += self.division_standings(self.league[subleague][division], standings)[:self.constraints["division_leaders"]]
|
||||
this_div_wildcard = [this_team for this_team, wins, losses, diff, gb in self.division_standings(self.league[subleague][division], standings)[self.constraints["division_leaders"]:]]
|
||||
subleague_array += this_div_wildcard
|
||||
if self.constraints["wild_cards"] > 0:
|
||||
wildcard_leaders = self.division_standings(subleague_array, standings)[:self.constraints["wild_cards"]]
|
||||
|
||||
for this_team, wins, losses, diff, gb in division_leaders + wildcard_leaders:
|
||||
team_dic[this_team] = {"wins" : wins}
|
||||
|
||||
subleague_tournament = tournament(f"{self.name} {subleague} Subleague Series", team_dic, series_length=3, finals_series_length=5, secs_between_games=int(3600/self.games_per_hour), secs_between_rounds=int(7200/self.games_per_hour))
|
||||
subleague_tournament.build_bracket(by_wins = True)
|
||||
subleague_tournament.league = self
|
||||
tournaments.append(subleague_tournament)
|
||||
|
||||
return tournaments
|
||||
|
||||
|
||||
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):
|
||||
self.name = name
|
||||
|
@ -217,6 +379,9 @@ class tournament(object):
|
|||
self.round_delay = secs_between_rounds
|
||||
self.finals = False
|
||||
self.id = id
|
||||
self.league = None
|
||||
self.winner = None
|
||||
self.day = None
|
||||
|
||||
if id is None:
|
||||
self.id = random.randint(1111,9999)
|
||||
|
@ -314,9 +479,7 @@ def save_league(this_league):
|
|||
with open(os.path.join(data_dir, league_dir, this_league.name, f"{this_league.name}.league"), "w") as league_file:
|
||||
league_json_string = jsonpickle.encode(this_league.league, keys=True)
|
||||
json.dump(league_json_string, league_file, indent=4)
|
||||
return True
|
||||
else:
|
||||
league_db.save_league(this_league)
|
||||
league_db.save_league(this_league)
|
||||
|
||||
def load_league_file(league_name):
|
||||
if league_db.league_exists(league_name):
|
||||
|
@ -329,7 +492,15 @@ def load_league_file(league_name):
|
|||
|
||||
this_league.day = state_dic["day"]
|
||||
this_league.schedule = state_dic["schedule"]
|
||||
this_league.constraints = state_dic["constraints"]
|
||||
this_league.game_length = state_dic["game_length"]
|
||||
this_league.series_length = state_dic["series_length"]
|
||||
this_league.owner = state_dic["owner"]
|
||||
this_league.games_per_hour = state_dic["games_per_hour"]
|
||||
this_league.historic = state_dic["historic"]
|
||||
this_league.season = state_dic["season"]
|
||||
try:
|
||||
this_league.champion = state_dic["champion"]
|
||||
except:
|
||||
this_league.champion = None
|
||||
return this_league
|
|
@ -97,6 +97,8 @@ def create_league():
|
|||
inter_division_games=config['inter_division_series'],
|
||||
inter_league_games=config['inter_league_series'],
|
||||
)
|
||||
new_league.constraints["division_leaders"] = config["top_postseason"]
|
||||
new_league.constraints["wild_cards"] = config["wildcards"]
|
||||
new_league.generate_schedule()
|
||||
leagues.save_league(new_league)
|
||||
|
||||
|
@ -199,6 +201,8 @@ def update_loop():
|
|||
if this_game.last_update[0]["defender"] != "":
|
||||
punc = ". "
|
||||
|
||||
|
||||
|
||||
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}"
|
||||
|
@ -209,6 +213,13 @@ def update_loop():
|
|||
|
||||
state["update_emoji"] = "🏏"
|
||||
state["update_text"] = updatestring
|
||||
|
||||
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 {games.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."
|
||||
|
||||
state["bases"] = this_game.named_bases()
|
||||
|
||||
|
@ -230,4 +241,4 @@ def update_loop():
|
|||
state["update_pause"] -= 1
|
||||
|
||||
socketio.emit("states_update", game_states)
|
||||
time.sleep(1)
|
||||
time.sleep(8)
|
1
simmadome/.eslintcache
Normal file
1
simmadome/.eslintcache
Normal file
|
@ -0,0 +1 @@
|
|||
[{"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\index.tsx":"1","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\reportWebVitals.ts":"2","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamesPage.tsx":"3","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamePage.tsx":"4","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamesUtil.tsx":"5","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\Game.tsx":"6","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\CreateLeague.tsx":"7","M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\util.tsx":"8"},{"size":2425,"mtime":1610685584594,"results":"9","hashOfConfig":"10"},{"size":440,"mtime":1610521673158,"results":"11","hashOfConfig":"10"},{"size":4866,"mtime":1610685584593,"results":"12","hashOfConfig":"10"},{"size":1897,"mtime":1610685584589,"results":"13","hashOfConfig":"10"},{"size":1157,"mtime":1610685584594,"results":"14","hashOfConfig":"10"},{"size":3173,"mtime":1610583643836,"results":"15","hashOfConfig":"10"},{"size":17241,"mtime":1610685584587,"results":"16","hashOfConfig":"10"},{"size":1029,"mtime":1610685584594,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1jg8ts7",{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"23","messages":"24","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"25","messages":"26","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"27","messages":"28","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"22"},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"33","messages":"34","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\index.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\reportWebVitals.ts",[],["35","36"],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamesPage.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamePage.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\GamesUtil.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\Game.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\CreateLeague.tsx",[],"M:\\Documents\\Code\\matteo\\the-prestige\\simmadome\\src\\util.tsx",["37"],{"ruleId":"38","replacedBy":"39"},{"ruleId":"40","replacedBy":"41"},{"ruleId":"42","severity":1,"message":"43","line":1,"column":9,"nodeType":"44","messageId":"45","endLine":1,"endColumn":15},"no-native-reassign",["46"],"no-negated-in-lhs",["47"],"@typescript-eslint/no-unused-vars","'useRef' is defined but never used.","Identifier","unusedVar","no-global-assign","no-unsafe-negation"]
|
|
@ -6,4 +6,4 @@ SELECT name,
|
|||
ROUND(strikeouts_given*27.0/(outs_pitched*1.0),3) as kper9,
|
||||
ROUND(strikeouts_given*1.0/walks_allowed*1.0,3) as kperbb
|
||||
FROM stats WHERE outs_pitched > 150
|
||||
ORDER BY bbper9 ASC;
|
||||
ORDER BY era ASC;
|
583
the_prestige.py
583
the_prestige.py
|
@ -1,7 +1,7 @@
|
|||
import discord, json, math, os, roman, games, asyncio, random, main_controller, threading, time, urllib, leagues, datetime
|
||||
import database as db
|
||||
import onomancer as ono
|
||||
from league_storage import league_exists
|
||||
from league_storage import league_exists, season_save
|
||||
from the_draft import Draft, DRAFT_ROUNDS
|
||||
from flask import Flask
|
||||
from uuid import uuid4
|
||||
|
@ -78,7 +78,7 @@ class IdolizeCommand(Command):
|
|||
else:
|
||||
meme = False
|
||||
|
||||
player_name = discord.utils.escape_mentions(command)
|
||||
player_name = discord.utils.escape_mentions(command.strip())
|
||||
if len(player_name) >= 70:
|
||||
await msg.channel.send("That name is too long. Please keep it below 70 characters, for my sake and yours.")
|
||||
return
|
||||
|
@ -202,7 +202,7 @@ class StartRandomGameCommand(Command):
|
|||
|
||||
channel = msg.channel
|
||||
await msg.delete()
|
||||
await channel.send("Rolling the bones...")
|
||||
await channel.send("Rolling the bones... This might take a while.")
|
||||
teamslist = games.get_all_teams()
|
||||
|
||||
game = games.game(random.choice(teamslist).finalize(), random.choice(teamslist).finalize())
|
||||
|
@ -562,7 +562,12 @@ class StartTournamentCommand(Command):
|
|||
if team == None:
|
||||
await msg.channel.send(f"We couldn't find {name}. Try again?")
|
||||
return
|
||||
team_dic[team] = {"wins": 0}
|
||||
add = True
|
||||
for extant_team in team_dic.keys():
|
||||
if extant_team.name == team.name:
|
||||
add = False
|
||||
if add:
|
||||
team_dic[team] = {"wins": 0}
|
||||
|
||||
channel = msg.channel
|
||||
await msg.delete()
|
||||
|
@ -596,8 +601,8 @@ class DraftPlayerCommand(Command):
|
|||
|
||||
class StartDraftCommand(Command):
|
||||
name = "startdraft"
|
||||
template = "m;startdraft [mention] [teamname] [slogan]"
|
||||
description = """Starts a draft with an arbitrary number of participants. Send this command at the top of the list with each mention, teamname, and slogan on a new line (shift+enter in discord).
|
||||
template = "m;startdraft\n[mention]\n[teamname]\n[slogan]"
|
||||
description = """Starts a draft with an arbitrary number of participants. Send this command at the top of the list with each mention, teamname, and slogan on their own lines (shift+enter in discord).
|
||||
- The draft will proceed in the order that participants were entered.
|
||||
- 20 players will be available for draft at a time, and the pool will refresh automatically when it becomes small.
|
||||
- Each participant will be asked to draft 12 hitters then finally one pitcher.
|
||||
|
@ -726,7 +731,7 @@ class StartDraftCommand(Command):
|
|||
return draft_message
|
||||
|
||||
class DebugLeagueStart(Command):
|
||||
name = "startleague"
|
||||
name = "startdebugleague"
|
||||
|
||||
async def execute(self, msg, command):
|
||||
if not league_exists("test2"):
|
||||
|
@ -743,19 +748,213 @@ class DebugLeagueStart(Command):
|
|||
}, division_games=6, inter_division_games=3, inter_league_games=3, games_per_hour = 12)
|
||||
league.generate_schedule()
|
||||
leagues.save_league(league)
|
||||
else:
|
||||
league = leagues.load_league_file("test2")
|
||||
await start_league_day(msg.channel, league, autoplay = 2)
|
||||
|
||||
class DebugLeagueDisplay(Command):
|
||||
name = "displayleague"
|
||||
name = "displaydebugleague"
|
||||
|
||||
async def execute(self, msg, command):
|
||||
if league_exists("test2"):
|
||||
league = leagues.load_league_file("test2")
|
||||
await msg.channel.send(embed=league.standings_embed())
|
||||
|
||||
if league_exists("Midseries"):
|
||||
league = leagues.load_league_file("Midseries")
|
||||
league.champion = "Butts"
|
||||
leagues.save_league(league)
|
||||
season_save(league)
|
||||
league.season_reset()
|
||||
|
||||
await msg.channel.send(embed=league.past_standings(1))
|
||||
|
||||
|
||||
class StartLeagueCommand(Command):
|
||||
name = "startleague"
|
||||
template = "m;startleague [league name]\n[games per hour]"
|
||||
description = """Optional flags for the first line: `--queue X` or `-q X` to play X number of series before stopping; `--noautopostseason` will pause the league before starting postseason.
|
||||
Plays a league with a given name, provided that league has been saved on the website. The games per hour sets how often the games will start. (e.g. GPH 2 will start games at X:00 and X:30)"""
|
||||
|
||||
async def execute(self, msg, command):
|
||||
if config()["game_freeze"]:
|
||||
await msg.channel.send("Patch incoming. We're not allowing new games right now.")
|
||||
return
|
||||
|
||||
league_name = command.split("-")[0].split("\n")[0].strip()
|
||||
autoplay = None
|
||||
|
||||
|
||||
try:
|
||||
if "--queue " in command:
|
||||
autoplay = int(command.split("--queue ")[1].split("\n")[0])
|
||||
elif "-q " in command:
|
||||
autoplay = int(command.split("-q ")[1].split("\n")[0])
|
||||
if autoplay is not None and autoplay <= 0:
|
||||
raise ValueError
|
||||
elif autoplay is None:
|
||||
autoplay = -1
|
||||
except ValueError:
|
||||
await msg.channel.send("Sorry boss, the queue flag needs a natural number. Any whole number over 0 will do just fine.")
|
||||
return
|
||||
except IndexError:
|
||||
await msg.channel.send("We need a games per hour number in the second line.")
|
||||
return
|
||||
|
||||
|
||||
|
||||
try:
|
||||
gph = int(command.split("\n")[1].strip())
|
||||
if gph < 1 or gph > 12:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
await msg.channel.send("Chief, we need a games per hour number between 1 and 12. We think that's reasonable.")
|
||||
return
|
||||
|
||||
if league_exists(league_name):
|
||||
league = leagues.load_league_file(league_name)
|
||||
if "--noautopostseason" in command:
|
||||
autoplay = int(list(league.schedule.keys())[-1]) - league.day_to_series_num(league.day) + 1
|
||||
|
||||
if league.historic:
|
||||
await msg.channel.send("That league is done and dusted, chief. Sorry.")
|
||||
return
|
||||
for active_league in active_leagues:
|
||||
if active_league.name == league.name:
|
||||
await msg.channel.send("That league is already running, boss. Patience is a virtue, you know.")
|
||||
return
|
||||
if (league.owner is not None and msg.author.id in league.owner) or msg.author.id in config()["owners"] or league.owner is None:
|
||||
league.autoplay = autoplay
|
||||
league.games_per_hour = gph
|
||||
if str(league.day_to_series_num(league.day)) not in league.schedule.keys():
|
||||
await league_postseason(msg.channel, league)
|
||||
elif league.day % league.series_length == 1:
|
||||
await start_league_day(msg.channel, league)
|
||||
else:
|
||||
await start_league_day(msg.channel, league, partial = True)
|
||||
else:
|
||||
await msg.channel.send("You don't have permission to manage that league.")
|
||||
return
|
||||
else:
|
||||
await msg.channel.send("Couldn't find that league, boss. Did you save it on the website?")
|
||||
|
||||
class LeagueDisplayCommand(Command):
|
||||
name = "leaguestandings"
|
||||
template = "m;leaguestandings [league name]"
|
||||
description = "Displays the current standings for the given league. Use `--season X` or `-s X` to get standings from season X of that league."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
if league_exists(command.split("-")[0].strip()):
|
||||
league = leagues.load_league_file(command.split("-")[0].strip())
|
||||
|
||||
try:
|
||||
if "--season " in command:
|
||||
season_num = int(command.split("--season ")[1])
|
||||
await msg.channel.send(embed=league.past_standings(season_num))
|
||||
elif "-s " in command:
|
||||
season_num = int(command.split("-s ")[1])
|
||||
await msg.channel.send(embed=league.past_standings(season_num))
|
||||
else:
|
||||
await msg.channel.send(embed=league.standings_embed())
|
||||
except ValueError:
|
||||
await msg.channel.send("Give us a proper number, boss.")
|
||||
except TypeError:
|
||||
await msg.channel.send("That season hasn't been played yet, chief.")
|
||||
else:
|
||||
await msg.channel.send("Can't find that league, boss.")
|
||||
|
||||
class LeagueWildcardCommand(Command):
|
||||
name = "leaguewildcard"
|
||||
template = "m;leaguewildcard [league name]"
|
||||
description = "Displays the current wildcard race for the given league, if the league has wildcard slots."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
if league_exists(command.strip()):
|
||||
league = leagues.load_league_file(command.strip())
|
||||
if league.constraints["wild_cards"] > 0:
|
||||
await msg.channel.send(embed=league.wildcard_embed())
|
||||
else:
|
||||
await msg.channel.send("That league doesn't have wildcards, boss.")
|
||||
else:
|
||||
await msg.channel.send("Can't find that league, boss.")
|
||||
|
||||
class LeaguePauseCommand(Command):
|
||||
name = "pauseleague"
|
||||
template = "m;pauseleague [league name]"
|
||||
descripton = "Tells a currently running league to stop running automatically after the current series."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
league_name = command.strip()
|
||||
for active_league in active_leagues:
|
||||
if active_league.name == league_name:
|
||||
if (active_league.owner is not None and msg.author.id in active_league.owner) or msg.author.id in config()["owners"]:
|
||||
active_league.autoplay = 0
|
||||
await msg.channel.send(f"Loud and clear, chief. {league_name} will stop after this series is over.")
|
||||
return
|
||||
else:
|
||||
await msg.channel.send("You don't have permission to manage that league.")
|
||||
return
|
||||
await msg.channel.send("That league either doesn't exist or isn't running.")
|
||||
|
||||
class LeagueClaimCommand(Command):
|
||||
name = "claimleague"
|
||||
template = "m;claimleague [league name]"
|
||||
description = "Claims an unclaimed league. Do this as soon as possible after creating the league, or it will remain unclaimed."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
league_name = command.strip()
|
||||
if league_exists(league_name):
|
||||
league = leagues.load_league_file(league_name)
|
||||
if league.owner is None:
|
||||
league.owner = [msg.author.id]
|
||||
leagues.save_league(league)
|
||||
await msg.channel.send(f"The {league.name} commissioner is doing a great job. That's you, by the way.")
|
||||
return
|
||||
else:
|
||||
await msg.channel.send("That league has already been claimed!")
|
||||
else:
|
||||
await msg.channel.send("Can't find that league, boss.")
|
||||
|
||||
class LeagueAddOwnersCommand(Command):
|
||||
name = "addleagueowner"
|
||||
template = "m;addleagueowner [league name]\n[user mentions]"
|
||||
description = "Adds additional owners to a league."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
league_name = command.split("\n")[0].strip()
|
||||
if league_exists(league_name):
|
||||
league = leagues.load_league_file(league_name)
|
||||
if (league.owner is not None and msg.author.id in league.owner) or (league.owner is not None and msg.author.id in config()["owners"]):
|
||||
for user in msg.mentions:
|
||||
if user.id not in league.owner:
|
||||
league.owner.append(user.id)
|
||||
leagues.save_league(league)
|
||||
await msg.channel.send(f"The new {league.name} front office is now up and running.")
|
||||
return
|
||||
else:
|
||||
await msg.channel.send(f"That league isn't yours, boss.")
|
||||
return
|
||||
else:
|
||||
await msg.channel.send("Can't find that league, boss.")
|
||||
|
||||
class LeagueScheduleCommand(Command):
|
||||
name = "leagueschedule"
|
||||
template = "m;leagueschedule [league name]"
|
||||
description = "Sends an embed with the given league's schedule for the next 4 series."
|
||||
|
||||
async def execute(self, msg, command):
|
||||
league_name = command.strip()
|
||||
if league_exists(league_name):
|
||||
league = leagues.load_league_file(league_name)
|
||||
current_series = league.day_to_series_num(league.day)
|
||||
if str(current_series+1) in league.schedule.keys():
|
||||
sched_embed = discord.Embed(title=f"{league.name}'s Schedule:")
|
||||
days = [0,1,2,3]
|
||||
for day in days:
|
||||
if str(current_series+day) in league.schedule.keys():
|
||||
schedule_text = ""
|
||||
for game in league.schedule[str(current_series+day)]:
|
||||
schedule_text += f"**{game[0]}** @ **{game[1]}**\n"
|
||||
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)
|
||||
await msg.channel.send(embed=sched_embed)
|
||||
else:
|
||||
await msg.channel.send("That league's already finished with this season, boss.")
|
||||
else:
|
||||
await msg.channel.send("We can't find that league. Typo?")
|
||||
|
||||
|
||||
commands = [
|
||||
IntroduceCommand(),
|
||||
|
@ -776,8 +975,15 @@ commands = [
|
|||
ShowAllTeamsCommand(),
|
||||
SearchTeamsCommand(),
|
||||
StartGameCommand(),
|
||||
StartTournamentCommand(),
|
||||
StartRandomGameCommand(),
|
||||
StartTournamentCommand(),
|
||||
LeagueClaimCommand(),
|
||||
LeagueAddOwnersCommand(),
|
||||
StartLeagueCommand(),
|
||||
LeaguePauseCommand(),
|
||||
LeagueDisplayCommand(),
|
||||
LeagueWildcardCommand(),
|
||||
LeagueScheduleCommand(),
|
||||
CreditCommand(),
|
||||
RomanCommand(),
|
||||
HelpCommand(),
|
||||
|
@ -1058,7 +1264,16 @@ async def start_tournament_round(channel, tourney, seeding = None):
|
|||
|
||||
for pair in games_to_start:
|
||||
if pair[0] is not None and pair[1] is not None:
|
||||
this_game = games.game(pair[0].prepare_for_save().finalize(), pair[1].prepare_for_save().finalize(), length = tourney.game_length)
|
||||
team_a = get_team_fuzzy_search(pair[0].name)
|
||||
team_b = get_team_fuzzy_search(pair[1].name)
|
||||
|
||||
if tourney.league is not None:
|
||||
if tourney.day is None:
|
||||
tourney.day = tourney.league.day
|
||||
team_a.set_pitcher(rotation_slot = tourney.day)
|
||||
team_b.set_pitcher(rotation_slot = tourney.day)
|
||||
|
||||
this_game = games.game(team_a.finalize(), team_b.finalize(), length = tourney.game_length)
|
||||
this_game, state_init = prepare_game(this_game)
|
||||
|
||||
state_init["is_league"] = True
|
||||
|
@ -1089,6 +1304,14 @@ async def continue_tournament_series(tourney, queue, games_list, wins_in_series)
|
|||
for oldgame in queue:
|
||||
away_team = games.get_team(oldgame.teams["away"].name)
|
||||
home_team = games.get_team(oldgame.teams["home"].name)
|
||||
|
||||
if tourney.league is not None:
|
||||
if tourney.day is None:
|
||||
tourney.day = tourney.league.day
|
||||
away_team.set_pitcher(rotation_slot = tourney.day)
|
||||
home_team.set_pitcher(rotation_slot = tourney.day)
|
||||
|
||||
|
||||
this_game = games.game(away_team.finalize(), home_team.finalize(), length = tourney.game_length)
|
||||
this_game, state_init = prepare_game(this_game)
|
||||
|
||||
|
@ -1120,7 +1343,7 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
|
|||
try:
|
||||
for i in range(0, len(games_list)):
|
||||
game, key = games_list[i]
|
||||
if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8:
|
||||
if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()):
|
||||
if game.teams['home'].name not in wins_in_series.keys():
|
||||
wins_in_series[game.teams["home"].name] = 0
|
||||
if game.teams['away'].name not in wins_in_series.keys():
|
||||
|
@ -1134,6 +1357,7 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
|
|||
wins_in_series[winner_name] = 1
|
||||
|
||||
final_embed = game_over_embed(game)
|
||||
final_embed.add_field(name="Series score:", value=f"{wins_in_series[game.teams['away'].name]} - {wins_in_series[game.teams['home'].name]}")
|
||||
await channel.send(f"A {tourney.name} game just ended!")
|
||||
await channel.send(embed=final_embed)
|
||||
if wins_in_series[winner_name] >= int((tourney.series_length+1)/2) and not finals:
|
||||
|
@ -1148,11 +1372,36 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
|
|||
except:
|
||||
print("something went wrong in tourney_watcher")
|
||||
await asyncio.sleep(4)
|
||||
|
||||
if tourney.league is not None:
|
||||
tourney.day += 1
|
||||
|
||||
if len(queued_games) > 0:
|
||||
await channel.send(f"The next batch of games for {tourney.name} will start in {int(tourney.delay/60)} minutes.")
|
||||
await asyncio.sleep(tourney.delay)
|
||||
|
||||
if tourney.league is not None:
|
||||
now = datetime.datetime.now()
|
||||
validminutes = [int((60 * div)/tourney.league.games_per_hour) for div in range(0,tourney.league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
await channel.send(f"The next batch of games for the {tourney.name} will start in {math.ceil(wait_seconds/60)} minutes.")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
else:
|
||||
await channel.send(f"The next batch of games for {tourney.name} will start in {int(tourney.delay/60)} minutes.")
|
||||
await asyncio.sleep(tourney.delay)
|
||||
await channel.send(f"{len(queued_games)} games for {tourney.name}, starting at {filter_url}")
|
||||
games_list = await continue_tournament_series(tourney, queued_games, games_list, wins_in_series)
|
||||
else:
|
||||
|
@ -1160,7 +1409,10 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
|
|||
|
||||
if finals: #if this last round was finals
|
||||
embed = discord.Embed(color = discord.Color.dark_purple(), title = f"{winner_list[0]} win the {tourney.name} finals!")
|
||||
if tourney.day > tourney.league.day:
|
||||
tourney.league.day = tourney.day
|
||||
await channel.send(embed=embed)
|
||||
tourney.winner = get_team_fuzzy_search(winner_list[0])
|
||||
active_tournaments.pop(active_tournaments.index(tourney))
|
||||
return
|
||||
|
||||
|
@ -1169,11 +1421,37 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
|
|||
winners_string = ""
|
||||
for game in tourney.bracket.get_bottom_row():
|
||||
winners_string += f"{game[0].name}\n{game[1].name}\n"
|
||||
await channel.send(f"""
|
||||
|
||||
if tourney.league is not None:
|
||||
now = datetime.datetime.now()
|
||||
validminutes = [int((60 * div)/tourney.league.games_per_hour) for div in range(0,tourney.league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
await channel.send(f"""This round of games for the {tourney.name} is now complete! The next round will start in {math.ceil(wait_seconds/60)} minutes.
|
||||
Advancing teams:
|
||||
{winners_string}""")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
else:
|
||||
await channel.send(f"""
|
||||
This round of games for {tourney.name} is now complete! The next round will be starting in {int(tourney.round_delay/60)} minutes.
|
||||
Advancing teams:
|
||||
{winners_string}""")
|
||||
await asyncio.sleep(tourney.round_delay)
|
||||
await asyncio.sleep(tourney.round_delay)
|
||||
await start_tournament_round(channel, tourney)
|
||||
|
||||
|
||||
|
@ -1373,7 +1651,7 @@ async def game_watcher():
|
|||
this_array = gamesarray.copy()
|
||||
for i in range(0,len(this_array)):
|
||||
game, channel, user, key = this_array[i]
|
||||
if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8:
|
||||
if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()):
|
||||
final_embed = game_over_embed(game)
|
||||
if isinstance(user, str):
|
||||
await channel.send(f"A game started by {user} just ended.")
|
||||
|
@ -1394,7 +1672,6 @@ def game_over_embed(game):
|
|||
title_string += f" with {game.inning - (game.max_innings+1)} extra innings.\n"
|
||||
else:
|
||||
title_string += ".\n"
|
||||
title_string += game.weather.emoji + game.weather.name
|
||||
|
||||
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"
|
||||
|
@ -1406,7 +1683,10 @@ def game_over_embed(game):
|
|||
winstring += f"{winning_team} wins!"
|
||||
|
||||
embed = discord.Embed(color=discord.Color.dark_purple(), title=title_string)
|
||||
embed.add_field(name="Final score:", value=winstring)
|
||||
embed.add_field(name="Final score:", value=winstring, inline=False)
|
||||
embed.add_field(name=f"{game.teams['away'].name} pitcher:", value=game.teams['away'].pitcher.name)
|
||||
embed.add_field(name=f"{game.teams['home'].name} pitcher:", value=game.teams['home'].pitcher.name)
|
||||
embed.set_footer(text=game.weather.emoji + game.weather.name)
|
||||
return embed
|
||||
|
||||
def get_team_fuzzy_search(team_name):
|
||||
|
@ -1417,7 +1697,7 @@ def get_team_fuzzy_search(team_name):
|
|||
team = teams[0]
|
||||
return team
|
||||
|
||||
async def start_league_day(channel, league, autoplay = 1):
|
||||
async def start_league_day(channel, league, partial = False):
|
||||
current_games = []
|
||||
|
||||
games_to_start = league.schedule[str(league.day_to_series_num(league.day))]
|
||||
|
@ -1437,8 +1717,11 @@ async def start_league_day(channel, league, autoplay = 1):
|
|||
this_game, state_init = prepare_game(this_game)
|
||||
|
||||
state_init["is_league"] = True
|
||||
series_string = f"Series score:"
|
||||
state_init["title"] = f"{series_string} 0 - 0"
|
||||
if not partial:
|
||||
series_string = "Series score:"
|
||||
state_init["title"] = f"{series_string} 0 - 0"
|
||||
else:
|
||||
state_init["title"] = "Interrupted series!"
|
||||
discrim_string = league.name
|
||||
|
||||
id = str(uuid4())
|
||||
|
@ -1448,67 +1731,74 @@ async def start_league_day(channel, league, autoplay = 1):
|
|||
ext = "?league=" + urllib.parse.quote_plus(league.name)
|
||||
|
||||
if league.last_series_check(): #if finals
|
||||
await channel.send(f"The final series of the {league.name} is starting now, at {config()['simmadome_url']+ext}")
|
||||
await channel.send(f"The final series of the {league.name} regular season is starting now, at {config()['simmadome_url']+ext}")
|
||||
last = True
|
||||
|
||||
else:
|
||||
await channel.send(f"The day {league.day} series of the {league.name} is starting now, at {config()['simmadome_url']+ext}")
|
||||
last = False
|
||||
|
||||
await league_day_watcher(channel, league, current_games, config()['simmadome_url']+ext, autoplay, last)
|
||||
if partial:
|
||||
missed_games = (league.day % league.series_length) - 1
|
||||
await league_day_watcher(channel, league, current_games, config()['simmadome_url']+ext, last, missed = missed_games)
|
||||
else:
|
||||
await league_day_watcher(channel, league, current_games, config()['simmadome_url']+ext, last)
|
||||
|
||||
|
||||
async def league_day_watcher(channel, league, games_list, filter_url, autoplay, last = False):
|
||||
async def league_day_watcher(channel, league, games_list, filter_url, last = False, missed = 0):
|
||||
league.active = True
|
||||
autoplay -= 1
|
||||
active_leagues.append(league)
|
||||
league.autoplay -= 1
|
||||
if league not in active_leagues:
|
||||
active_leagues.append(league)
|
||||
series_results = {}
|
||||
|
||||
while league.active:
|
||||
queued_games = []
|
||||
while len(games_list) > 0:
|
||||
#try:
|
||||
for i in range(0, len(games_list)):
|
||||
game, key = games_list[i]
|
||||
if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8:
|
||||
if game.teams['home'].name not in series_results.keys():
|
||||
series_results[game.teams["home"].name] = {}
|
||||
series_results[game.teams["home"].name]["wins"] = 0
|
||||
series_results[game.teams["home"].name]["losses"] = 0
|
||||
series_results[game.teams["home"].name]["run_diff"] = 0
|
||||
if game.teams['away'].name not in series_results.keys():
|
||||
series_results[game.teams["away"].name] = {}
|
||||
series_results[game.teams["away"].name]["wins"] = 0
|
||||
series_results[game.teams["away"].name]["losses"] = 0
|
||||
series_results[game.teams["away"].name]["run_diff"] = 0
|
||||
try:
|
||||
for i in range(0, len(games_list)):
|
||||
game, key = games_list[i]
|
||||
if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()):
|
||||
if game.teams['home'].name not in series_results.keys():
|
||||
series_results[game.teams["home"].name] = {}
|
||||
series_results[game.teams["home"].name]["wins"] = 0
|
||||
series_results[game.teams["home"].name]["losses"] = 0
|
||||
series_results[game.teams["home"].name]["run_diff"] = 0
|
||||
if game.teams['away'].name not in series_results.keys():
|
||||
series_results[game.teams["away"].name] = {}
|
||||
series_results[game.teams["away"].name]["wins"] = 0
|
||||
series_results[game.teams["away"].name]["losses"] = 0
|
||||
series_results[game.teams["away"].name]["run_diff"] = 0
|
||||
|
||||
winner_name = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name
|
||||
loser_name = game.teams['away'].name if game.teams['home'].score > game.teams['away'].score else game.teams['home'].name
|
||||
rd = int(math.fabs(game.teams['home'].score - game.teams['away'].score))
|
||||
winner_name = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name
|
||||
loser_name = game.teams['away'].name if game.teams['home'].score > game.teams['away'].score else game.teams['home'].name
|
||||
rd = int(math.fabs(game.teams['home'].score - game.teams['away'].score))
|
||||
|
||||
series_results[winner_name]["wins"] += 1
|
||||
series_results[winner_name]["run_diff"] += rd
|
||||
series_results[winner_name]["wins"] += 1
|
||||
series_results[winner_name]["run_diff"] += rd
|
||||
|
||||
winner_dic = {"wins" : 1, "run_diff" : rd}
|
||||
winner_dic = {"wins" : 1, "run_diff" : rd}
|
||||
|
||||
series_results[loser_name]["losses"] += 1
|
||||
series_results[loser_name]["run_diff"] -= rd
|
||||
series_results[loser_name]["losses"] += 1
|
||||
series_results[loser_name]["run_diff"] -= rd
|
||||
|
||||
loser_dic = {"losses" : 1, "run_diff" : -rd}
|
||||
loser_dic = {"losses" : 1, "run_diff" : -rd}
|
||||
|
||||
league.add_stats_from_game(game.get_team_specific_stats())
|
||||
league.update_standings({winner_name : winner_dic, loser_name : loser_dic})
|
||||
leagues.save_league(league)
|
||||
final_embed = game_over_embed(game)
|
||||
await channel.send(f"A {league.name} game just ended!")
|
||||
await channel.send(embed=final_embed)
|
||||
if series_results[winner_name]["wins"] + series_results[winner_name]["losses"] < league.series_length:
|
||||
queued_games.append(game)
|
||||
games_list.pop(i)
|
||||
break
|
||||
#except:
|
||||
#print("something went wrong in league_day_watcher")
|
||||
await asyncio.sleep(1)
|
||||
league.add_stats_from_game(game.get_team_specific_stats())
|
||||
league.update_standings({winner_name : winner_dic, loser_name : loser_dic})
|
||||
leagues.save_league(league)
|
||||
final_embed = game_over_embed(game)
|
||||
final_embed.add_field(name="Day:", value=league.day)
|
||||
final_embed.add_field(name="Series score:", value=f"{series_results[game.teams['away'].name]['wins']} - {series_results[game.teams['home'].name]['wins']}")
|
||||
await channel.send(f"A {league.name} game just ended!")
|
||||
await channel.send(embed=final_embed)
|
||||
if series_results[winner_name]["wins"] + series_results[winner_name]["losses"] + missed < league.series_length:
|
||||
queued_games.append(game)
|
||||
games_list.pop(i)
|
||||
break
|
||||
except:
|
||||
print("something went wrong in league_day_watcher")
|
||||
await asyncio.sleep(2)
|
||||
league.day += 1
|
||||
|
||||
if len(queued_games) > 0:
|
||||
|
@ -1518,8 +1808,16 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay,
|
|||
validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-1:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
|
@ -1532,30 +1830,72 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay,
|
|||
leagues.save_league(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)
|
||||
games_list = await continue_league_series(league, queued_games, games_list, series_results, missed)
|
||||
else:
|
||||
league.active = False
|
||||
|
||||
|
||||
|
||||
|
||||
if last or autoplay == 0: #if this series was the last of the season OR number of series to autoplay has been reached
|
||||
if league.autoplay == 0 or config()["game_freeze"]: #if number of series to autoplay has been reached
|
||||
await channel.send(embed=league.standings_embed())
|
||||
await channel.send(f"The {league.name} is no longer autoplaying.")
|
||||
if config()["game_freeze"]:
|
||||
await channel.send("Patch incoming.")
|
||||
leagues.save_league(league)
|
||||
active_leagues.pop(active_leagues.index(league))
|
||||
return
|
||||
|
||||
if last: #if last game of the season
|
||||
now = datetime.datetime.now()
|
||||
validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
await channel.send(f"This {league.name} season is now over! The postseason (with any necessary tiebreakers) will be starting in {math.ceil(wait_seconds/60)} minutes.")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
await league_postseason(channel, league)
|
||||
|
||||
#need to reset league to new season here
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i < len(validminutes)-1:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(microsecond=0)
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
|
||||
leagues.save_league(league)
|
||||
|
@ -1563,9 +1903,9 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay,
|
|||
await channel.send(f"""This {league.name} series is now complete! The next series will be starting in {int(wait_seconds/60)} minutes.""")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
|
||||
await start_league_day(channel, league, autoplay)
|
||||
await start_league_day(channel, league)
|
||||
|
||||
async def continue_league_series(league, queue, games_list, series_results):
|
||||
async def continue_league_series(league, queue, games_list, series_results, missed):
|
||||
for oldgame in queue:
|
||||
away_team = games.get_team(oldgame.teams["away"].name)
|
||||
away_team.set_pitcher(rotation_slot=league.day)
|
||||
|
@ -1576,7 +1916,12 @@ async def continue_league_series(league, queue, games_list, series_results):
|
|||
|
||||
state_init["is_league"] = True
|
||||
series_string = f"Series score:"
|
||||
state_init["title"] = f"{series_string} {series_results[away_team.name]['wins']} - {series_results[home_team.name]['wins']}"
|
||||
|
||||
if missed <= 0:
|
||||
series_string = "Series score:"
|
||||
state_init["title"] = f"{series_string} {series_results[away_team.name]['wins']} - {series_results[home_team.name]['wins']}"
|
||||
else:
|
||||
state_init["title"] = "Interrupted series!"
|
||||
discrim_string = league.name
|
||||
|
||||
id = str(uuid4())
|
||||
|
@ -1585,8 +1930,80 @@ async def continue_league_series(league, queue, games_list, series_results):
|
|||
|
||||
return games_list
|
||||
|
||||
async def league_postseason(channel, league):
|
||||
embed = league.standings_embed()
|
||||
embed.set_footer(text="Final Standings")
|
||||
await channel.send(embed=embed)
|
||||
|
||||
|
||||
tiebreakers = league.tiebreaker_required()
|
||||
if tiebreakers != []:
|
||||
await channel.send("Tiebreakers required!")
|
||||
await asyncio.gather(*[start_tournament_round(channel, tourney) for tourney in tiebreakers])
|
||||
for tourney in tiebreakers:
|
||||
league.update_standings({tourney.winner.name : {"wins" : 1}})
|
||||
leagues.save_league(league)
|
||||
now = datetime.datetime.now()
|
||||
|
||||
validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
await channel.send(f"Tiebreakers complete! Postseason starting in {math.ceil(wait_seconds/60)} minutes.")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
|
||||
|
||||
tourneys = league.champ_series()
|
||||
await asyncio.gather(*[start_tournament_round(channel, tourney) for tourney in tourneys])
|
||||
champs = {}
|
||||
for tourney in tourneys:
|
||||
for team in tourney.teams.keys():
|
||||
if team.name == tourney.winner.name:
|
||||
champs[tourney.winner] = {"wins" : tourney.teams[team]["wins"]}
|
||||
world_series = leagues.tournament(f"{league.name} Championship Series", champs, series_length=7, secs_between_games=int(3600/league.games_per_hour), secs_between_rounds=int(7200/league.games_per_hour))
|
||||
world_series.build_bracket(by_wins = True)
|
||||
world_series.league = league
|
||||
now = datetime.datetime.now()
|
||||
|
||||
validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)]
|
||||
for i in range(0, len(validminutes)):
|
||||
if now.minute > validminutes[i]:
|
||||
if i <= len(validminutes)-3:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
elif i <= len(validminutes)-2:
|
||||
if validminutes[i+1] == now.minute:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute))
|
||||
else:
|
||||
delta = datetime.timedelta(minutes= (60 - now.minute))
|
||||
|
||||
next_start = (now + delta).replace(second=0, microsecond=0)
|
||||
wait_seconds = (next_start - now).seconds
|
||||
await channel.send(f"The {league.name} Championship Series is starting in {math.ceil(wait_seconds/60)} minutes!")
|
||||
await asyncio.sleep(wait_seconds)
|
||||
await start_tournament_round(channel, world_series)
|
||||
league.champion = world_series.winner.name
|
||||
leagues.save_league(league)
|
||||
season_save(league)
|
||||
league.season_reset()
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user