hillexed 2021-02-21 18:45:37 -05:00
commit c0e85b87ec
6 changed files with 173 additions and 34 deletions

View file

@ -158,6 +158,7 @@ these folks are helping me a *ton* via patreon, and i cannot possibly thank them
- Evie Diver - Evie Diver
- iliana etaoin - iliana etaoin
- yooori - yooori
- Bend
## Attribution ## Attribution

View file

@ -30,7 +30,6 @@ def config():
return json.load(config_file) return json.load(config_file)
class player(object): class player(object):
def __init__(self, json_string): def __init__(self, json_string):
self.stlats = json.loads(json_string) self.stlats = json.loads(json_string)
@ -791,4 +790,3 @@ def search_team(search_term):
teams.append(team_json) teams.append(team_json)
return teams return teams

View file

@ -34,11 +34,16 @@ def statements():
ROUND(total_bases*1.0 / (plate_appearances - (walks_taken + sacrifices)*1.0),3) as SLG, ROUND(total_bases*1.0 / (plate_appearances - (walks_taken + sacrifices)*1.0),3) as SLG,
ROUND((walks_taken + hits)*1.0/plate_appearances*1.0,3) as OBP, ROUND((walks_taken + hits)*1.0/plate_appearances*1.0,3) as OBP,
ROUND((walks_taken + hits)*1.0/plate_appearances*1.0,3) + ROUND(total_bases*1.0 / (plate_appearances - (walks_taken + sacrifices)*1.0),3) as OPS ROUND((walks_taken + hits)*1.0/plate_appearances*1.0,3) + ROUND(total_bases*1.0 / (plate_appearances - (walks_taken + sacrifices)*1.0),3) as OPS
FROM stats WHERE plate_appearances > 8""", FROM stats WHERE plate_appearances > """,
"bat_base_req": 3,
"avg" : ["ORDER BY BA DESC;", "bat_base"], "avg" : ["ORDER BY BA DESC;", "bat_base"],
"slg" : ["ORDER BY SLG DESC;", "bat_base"], "slg" : ["ORDER BY SLG DESC;", "bat_base"],
"obp" : ["ORDER BY OBP DESC;", "bat_base"], "obp" : ["ORDER BY OBP DESC;", "bat_base"],
"ops" : ["ORDER BY OPS DESC;", "bat_base"], "ops" : ["ORDER BY OPS DESC;", "bat_base"],
"bat_count_base": "SELECT name, team_name,\n\tplate_appearances - (walks_taken + sacrifices) as ABs,\nwalks_taken as BB,\nhits as H,\nhome_runs as HR,\nrbis as RBIs,\nstrikeouts_taken as K,\nsacrifices\nFROM stats WHERE plate_appearances > 8",
"home runs": ["ORDER BY HR DESC;", "bat_count_base"],
"walks drawn": ["ORDER BY BB DESC;", "bat_count_base"],
"bat_count_base_req" : 3,
"pitch_base" : """SELECT name, team_name, "pitch_base" : """SELECT name, team_name,
ROUND(((outs_pitched*1.0)/3.0),1) as IP, ROUND(((outs_pitched*1.0)/3.0),1) as IP,
ROUND(runs_allowed*27.0/(outs_pitched*1.0),3) as ERA, ROUND(runs_allowed*27.0/(outs_pitched*1.0),3) as ERA,
@ -46,8 +51,9 @@ FROM stats WHERE plate_appearances > 8""",
ROUND(walks_allowed*27.0/(outs_pitched*1.0),3) as BBper9, ROUND(walks_allowed*27.0/(outs_pitched*1.0),3) as BBper9,
ROUND(strikeouts_given*27.0/(outs_pitched*1.0),3) as Kper9, ROUND(strikeouts_given*27.0/(outs_pitched*1.0),3) as Kper9,
ROUND(strikeouts_given*1.0/walks_allowed*1.0,3) as KperBB ROUND(strikeouts_given*1.0/walks_allowed*1.0,3) as KperBB
FROM stats WHERE outs_pitched > 20 FROM stats WHERE outs_pitched >
""", """,
"pitch_base_req": 2,
"era" : ["ORDER BY ERA ASC;", "pitch_base"], "era" : ["ORDER BY ERA ASC;", "pitch_base"],
"whip" : ["ORDER BY WHIP ASC;", "pitch_base"], "whip" : ["ORDER BY WHIP ASC;", "pitch_base"],
"kper9" : ["ORDER BY Kper9 DESC;", "pitch_base"], "kper9" : ["ORDER BY Kper9 DESC;", "pitch_base"],
@ -85,6 +91,9 @@ def state(league_name):
return json.load(state_file) return json.load(state_file)
def init_league_db(league): def init_league_db(league):
if os.path.exists(os.path.join(data_dir, league_dir, league.name, f"{league.name}.db")):
os.remove(os.path.join(data_dir, league_dir, league.name, f"{league.name}.db"))
conn = create_connection(league.name) conn = create_connection(league.name)
player_stats_table_check_string = """ CREATE TABLE IF NOT EXISTS stats ( player_stats_table_check_string = """ CREATE TABLE IF NOT EXISTS stats (
@ -169,7 +178,7 @@ def add_stats(league_name, player_game_stats_list):
conn.commit() conn.commit()
conn.close() conn.close()
def get_stats(league_name, stat, is_batter=True): def get_stats(league_name, stat, is_batter=True, day = 10):
conn = create_connection(league_name) conn = create_connection(league_name)
stats = None stats = None
if conn is not None: if conn is not None:
@ -177,7 +186,8 @@ def get_stats(league_name, stat, is_batter=True):
c=conn.cursor() c=conn.cursor()
if stat in statements().keys(): if stat in statements().keys():
c.execute(statements()[statements()[stat][1]]+"\n"+statements()[stat][0]) req_number = str(day * int(statements()[statements()[stat][1]+"_req"]))
c.execute(statements()[statements()[stat][1]]+req_number+"\n"+statements()[stat][0])
stats = c.fetchall() stats = c.fetchall()
conn.close() conn.close()
return stats return stats

View file

@ -89,11 +89,13 @@ class league_structure(object):
tournaments.append(tourney) tournaments.append(tourney)
return tournaments return tournaments
def find_team(self, team_name): def find_team(self, team_search):
for subleague in iter(self.league.keys()): for subleague in iter(self.league.keys()):
for division in iter(self.league[subleague].keys()): for division in iter(self.league[subleague].keys()):
if team_name in self.league[subleague][division]: for team in self.league[subleague][division]:
if team.name == team_search.name:
return (subleague, division) return (subleague, division)
return (None, None)
def teams_in_league(self): def teams_in_league(self):
teams = [] teams = []
@ -417,7 +419,7 @@ class league_structure(object):
def stat_embed(self, stat_name): def stat_embed(self, stat_name):
this_embed = Embed(color=Color.purple(), title=f"{self.name} Season {self.season} {stat_name} Leaders") this_embed = Embed(color=Color.purple(), title=f"{self.name} Season {self.season} {stat_name} Leaders")
stats = league_db.get_stats(self.name, stat_name.lower()) stats = league_db.get_stats(self.name, stat_name.lower(), day = self.day)
if stats is None: if stats is None:
return None return None
else: else:
@ -548,6 +550,13 @@ def save_league(this_league):
json.dump(league_json_string, league_file, indent=4) json.dump(league_json_string, league_file, indent=4)
league_db.save_league(this_league) league_db.save_league(this_league)
def save_league_as_new(this_league):
league_db.init_league_db(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)
league_db.save_league(this_league)
def load_league_file(league_name): def load_league_file(league_name):
if league_db.league_exists(league_name): if league_db.league_exists(league_name):
state = league_db.state(league_name) state = league_db.state(league_name)

View file

@ -146,6 +146,12 @@ class StartGameCommand(Command):
await msg.channel.send("Make sure you put an integer after the -d flag.") await msg.channel.send("Make sure you put an integer after the -d flag.")
return return
weather_name = None
if "-w " in command.split("\n")[0]:
weather_name = command.split("\n")[0].split("-w ")[1].split("-")[0].strip()
elif "--weather " in command.split("\n")[0]:
weather_name = command.split("\n")[0].split("--weather ")[1].split("-")[0].strip()
innings = None innings = None
try: try:
team_name1 = command.split("\n")[1].strip() team_name1 = command.split("\n")[1].strip()
@ -183,7 +189,10 @@ class StartGameCommand(Command):
game.teams['away'].set_pitcher(rotation_slot = day) game.teams['away'].set_pitcher(rotation_slot = day)
game.teams['home'].set_pitcher(rotation_slot = day) game.teams['home'].set_pitcher(rotation_slot = day)
channel = msg.channel channel = msg.channel
await msg.delete()
if weather_name is not None and weather_name in weather.all_weathers().keys():
game.weather = weather.all_weathers()[weather_name](game)
game_task = asyncio.create_task(watch_game(channel, game, user=msg.author, league=league)) game_task = asyncio.create_task(watch_game(channel, game, user=msg.author, league=league))
await game_task await game_task
@ -202,7 +211,6 @@ class StartRandomGameCommand(Command):
return return
channel = msg.channel channel = msg.channel
await msg.delete()
await channel.send("Rolling the bones... This might take a while.") await channel.send("Rolling the bones... This might take a while.")
teamslist = games.get_all_teams() teamslist = games.get_all_teams()
@ -1117,7 +1125,113 @@ class LeagueForceStopCommand(Command):
return return
await msg.channel.send("That league either doesn't exist or isn't in the active list. So, huzzah?") await msg.channel.send("That league either doesn't exist or isn't in the active list. So, huzzah?")
class LeagueSwapTeamCommand(Command):
name = "leagueswapteam"
template = "m;leagueswapteam [league name]\n[team to remove]\n[team to add]"
description = "Adds a team to a league, removing the old one in the process. Can only be executed by a league owner, and only before the start of a new season."
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.day != 1:
await msg.channel.send("That league hasn't finished its current season yet, chief. Either reset it, or be patient.")
return
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"]):
try:
team_del = get_team_fuzzy_search(command.split("\n")[1].strip())
team_add = get_team_fuzzy_search(command.split("\n")[2].strip())
except IndexError:
await msg.channel.send("Three lines, boss. Make sure you give us the team to remove, then the team to add.")
return
if team_add.name == team_del.name:
await msg.channel.send("Quit being cheeky. The teams have to be different.")
return
if team_del is None or team_add is None:
await msg.channel.send("We couldn't find one or both of those teams, boss. Try again.")
return
subleague, division = league.find_team(team_del)
if subleague is None or division is None:
await msg.channel.send("That first team isn't in that league, chief. So, that's good, right?")
return
if league.find_team(team_add)[0] is not None:
await msg.channel.send("That second team is already in that league, chief. No doubles.")
return
for index in range(0, len(league.league[subleague][division])):
if league.league[subleague][division][index].name == team_del.name:
league.league[subleague][division].pop(index)
league.league[subleague][division].append(team_add)
league.schedule = {}
league.generate_schedule()
leagues.save_league_as_new(league)
await msg.channel.send(embed=league.standings_embed())
await msg.channel.send("Paperwork signed, stamped, copied, and faxed up to the goddess. Xie's pretty quick with this stuff.")
else:
await msg.channel.send("That league isn't yours, chief.")
else:
await msg.channel.send("We can't find that league.")
class LeagueRenameCommand(Command):
name = "leaguerename"
template = "m;leaguerename [league name]\n[old subleague/division name]\n[new subleague/division name]"
description = "Changes the name of an existing subleague or division. Can only be executed by a league owner, and only before the start of a new season."
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.day != 1:
await msg.channel.send("That league hasn't finished its current season yet, chief. Either reset it, or be patient.")
return
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"]):
try:
old_name = command.split("\n")[1].strip()
new_name = command.split("\n")[2].strip()
except IndexError:
await msg.channel.send("Three lines, boss. Make sure you give us the old name, then the new name, on their own lines.")
return
if old_name == new_name:
await msg.channel.send("Quit being cheeky. They have to be different names, clearly.")
found = False
for subleague in league.league.keys():
if subleague == new_name:
found = True
break
for division in league.league[subleague]:
if division == new_name:
found = True
break
if found:
await msg.channel.send(f"{new_name} is already present in that league, chief. They have to be different.")
found = False
for subleague in league.league.keys():
if subleague == old_name:
league.league[new_name] = league.league.pop(old_name)
found = True
break
for division in league.league[subleague]:
if division == old_name:
league.league[subleague][new_name] = league.league[subleague].pop(old_name)
found = True
break
if not found:
await msg.channel.send(f"We couldn't find {old_name} anywhere in that league, boss.")
return
leagues.save_league_as_new(league)
await msg.channel.send(embed=league.standings_embed())
await msg.channel.send("Paperwork signed, stamped, copied, and faxed up to the goddess. Xie's pretty quick with this stuff.")
else:
await msg.channel.send("That league isn't yours, chief.")
else:
await msg.channel.send("We can't find that league.")
commands = [ commands = [
@ -1153,6 +1267,8 @@ commands = [
LeagueScheduleCommand(), LeagueScheduleCommand(),
LeagueTeamScheduleCommand(), LeagueTeamScheduleCommand(),
LeagueRegenerateScheduleCommand(), LeagueRegenerateScheduleCommand(),
LeagueSwapTeamCommand(),
LeagueRenameCommand(),
LeagueForceStopCommand(), LeagueForceStopCommand(),
CreditCommand(), CreditCommand(),
RomanCommand(), RomanCommand(),
@ -1161,6 +1277,7 @@ commands = [
DraftPlayerCommand() DraftPlayerCommand()
] ]
watching = False
client = discord.Client() client = discord.Client()
gamesarray = [] gamesarray = []
active_tournaments = [] active_tournaments = []
@ -1168,6 +1285,7 @@ active_leagues = []
active_standings = {} active_standings = {}
setupmessages = {} setupmessages = {}
thread1 = threading.Thread(target=main_controller.update_loop) thread1 = threading.Thread(target=main_controller.update_loop)
thread1.start() thread1.start()
@ -1196,8 +1314,11 @@ def config():
@client.event @client.event
async def on_ready(): async def on_ready():
global watching
db.initialcheck() db.initialcheck()
print(f"logged in as {client.user} with token {config()['token']} to {len(client.guilds)} servers") print(f"logged in as {client.user} with token {config()['token']} to {len(client.guilds)} servers")
if not watching:
watching = True
watch_task = asyncio.create_task(game_watcher()) watch_task = asyncio.create_task(game_watcher())
await watch_task await watch_task
@ -1396,7 +1517,7 @@ async def watch_game(channel, newgame, user = None, league = None):
main_controller.master_games_dic[id] = (newgame, state_init, discrim_string) main_controller.master_games_dic[id] = (newgame, state_init, discrim_string)
def prepare_game(newgame, league = None, weather_name = None): def prepare_game(newgame, league = None, weather_name = None):
if weather_name is None: if weather_name is None and newgame.weather.name == "Sunny":
weathers = weather.all_weathers() weathers = weather.all_weathers()
newgame.weather = weathers[random.choice(list(weathers.keys()))](newgame) newgame.weather = weathers[random.choice(list(weathers.keys()))](newgame)
@ -1575,7 +1696,7 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals
if finals: #if this last round was 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!") embed = discord.Embed(color = discord.Color.dark_purple(), title = f"{winner_list[0]} win the {tourney.name} finals!")
if tourney.day > tourney.league.day: if tourney.league is not None and tourney.day > tourney.league.day:
tourney.league.day = tourney.day tourney.league.day = tourney.day
await channel.send(embed=embed) await channel.send(embed=embed)
tourney.winner = get_team_fuzzy_search(winner_list[0]) tourney.winner = get_team_fuzzy_search(winner_list[0])
@ -2005,7 +2126,7 @@ async def league_day_watcher(channel, league, games_list, filter_url, last = Fal
else: else:
league.active = False league.active = False
if league.autoplay == 0 or config()["game_freeze"]: #if 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
if league in active_standings.keys(): if league in active_standings.keys():
await active_standings[league].unpin() await active_standings[league].unpin()
active_standings[league] = await channel.send(embed=league.standings_embed()) active_standings[league] = await channel.send(embed=league.standings_embed())

View file

@ -5,7 +5,7 @@ from gametext import appearance_outcomes, base_string
class Weather: class Weather:
def __init__(self, game): def __init__(self, game):
self.name = "Sunny" self.name = "Sunny"
self.emoji = "🌞" + "\uFE00" self.emoji = "🌞"
def __str__(self): def __str__(self):
return f"{self.emoji} {self.name}" return f"{self.emoji} {self.name}"
@ -38,18 +38,18 @@ class Weather:
pass pass
class Supernova(Weather): # todo class Supernova(Weather):
def __init__(self, game): def __init__(self, game):
self.name = "Supernova" self.name = "Supernova"
self.emoji = "🌟" + "\uFE00" self.emoji = "🌟"
def modify_atbat_stats(self, roll): def modify_atbat_stats(self, roll):
roll["pitch_stat"] *= 0.9 roll["pitch_stat"] *= 0.9
class Midnight(Weather): # todo class Midnight(Weather):
def __init__(self, game): def __init__(self, game):
self.name = "Midnight" self.name = "Midnight"
self.emoji = "🕶" + "\uFE00" self.emoji = "🕶"
def modify_steal_stats(self, roll): def modify_steal_stats(self, roll):
roll["run_stars"] *= 2 roll["run_stars"] *= 2
@ -57,7 +57,7 @@ class Midnight(Weather): # todo
class SlightTailwind(Weather): class SlightTailwind(Weather):
def __init__(self, game): def __init__(self, game):
self.name = "Slight Tailwind" self.name = "Slight Tailwind"
self.emoji = "🏌️‍♀️" + "\uFE00" self.emoji = "🏌️‍♀️"
def activate(self, game, result): def activate(self, game, result):
if game.top_of_inning: if game.top_of_inning:
@ -82,7 +82,7 @@ class SlightTailwind(Weather):
class HeavySnow(Weather): class HeavySnow(Weather):
def __init__(self, game): def __init__(self, game):
self.name = "Heavy Snow" self.name = "Heavy Snow"
self.emoji = "" + "\uFE00" self.emoji = ""
self.counter_away = random.randint(0,len(game.teams['away'].lineup)-1) self.counter_away = random.randint(0,len(game.teams['away'].lineup)-1)
self.counter_home = random.randint(0,len(game.teams['home'].lineup)-1) self.counter_home = random.randint(0,len(game.teams['home'].lineup)-1)
@ -127,7 +127,7 @@ class HeavySnow(Weather):
class Twilight(Weather): class Twilight(Weather):
def __init__(self,game): def __init__(self,game):
self.name = "Twilight" self.name = "Twilight"
self.emoji = "👻" + "\uFE00" self.emoji = "👻"
def modify_atbat_roll(self, outcome, roll, defender): def modify_atbat_roll(self, outcome, roll, defender):
error_line = - (math.log(defender.stlats["defense_stars"] + 1)/50) + 1 error_line = - (math.log(defender.stlats["defense_stars"] + 1)/50) + 1
@ -143,12 +143,12 @@ class Twilight(Weather):
if "error" in result.keys(): if "error" in result.keys():
state["update_text"] = f"{result['batter']}'s hit goes ethereal, and {result['defender']} can't catch it! {result['batter']} reaches base safely." state["update_text"] = f"{result['batter']}'s hit goes ethereal, and {result['defender']} can't catch it! {result['batter']} reaches base safely."
if this_game.last_update[1] > 0: if this_game.last_update[1] > 0:
state["update_text"] += f"{this_game.last_update[1]} runs scored!" state["update_text"] += f" {this_game.last_update[1]} runs scored!"
class ThinnedVeil(Weather): class ThinnedVeil(Weather):
def __init__(self,game): def __init__(self,game):
self.name = "Thinned Veil" self.name = "Thinned Veil"
self.emoji = "🌌" + "\uFE00" self.emoji = "🌌"
def activate(self, game, result): def activate(self, game, result):
if result["ishit"]: if result["ishit"]:
@ -163,7 +163,7 @@ class ThinnedVeil(Weather):
class HeatWave(Weather): class HeatWave(Weather):
def __init__(self,game): def __init__(self,game):
self.name = "Heat Wave" self.name = "Heat Wave"
self.emoji = "🌄" + "\uFE00" self.emoji = "🌄"
self.counter_away = random.randint(2,4) self.counter_away = random.randint(2,4)
self.counter_home = random.randint(2,4) self.counter_home = random.randint(2,4)
@ -225,7 +225,7 @@ class Drizzle(Weather):
placed_player = game.teams[next_team].lineup[(game.teams[next_team].lineup_position-1) % len(game.teams[next_team].lineup)] placed_player = game.teams[next_team].lineup[(game.teams[next_team].lineup_position-1) % len(game.teams[next_team].lineup)]
state["update_emoji"] = self.emoji state["update_emoji"] = self.emoji
state["update_text"] += f'Due to inclement weather, {placed_player.name} is placed on second base.' state["update_text"] += f' Due to inclement weather, {placed_player.name} is placed on second base.'
class Sun2(Weather): class Sun2(Weather):
@ -327,9 +327,9 @@ class Feedback(Weather):
def all_weathers(): def all_weathers():
weathers_dic = { weathers_dic = {
#"Supernova" : Supernova, "Supernova" : Supernova,
#"Midnight": Midnight, "Midnight": Midnight,
#"Slight Tailwind": SlightTailwind, "Slight Tailwind": SlightTailwind,
"Heavy Snow": HeavySnow, "Heavy Snow": HeavySnow,
"Twilight" : Twilight, "Twilight" : Twilight,
"Thinned Veil" : ThinnedVeil, "Thinned Veil" : ThinnedVeil,