diff --git a/database.py b/database.py index 79b5e49..a53da43 100644 --- a/database.py +++ b/database.py @@ -207,6 +207,21 @@ def save_team(name, team_json_string, user_id): except: return False +def update_team(name, team_json_string): + conn = create_connection() + try: + if conn is not None: + c = conn.cursor() + store_string = "UPDATE teams SET team_json_string = ? WHERE name=?" + c.execute(store_string, (team_json_string, (re.sub('[^A-Za-z0-9 ]+', '', name)))) #this regex removes all non-standard characters + conn.commit() + conn.close() + return True + conn.close() + return False + except: + return False + def get_team(name, owner=False): conn = create_connection() if conn is not None: diff --git a/games.py b/games.py index 805e4c4..a077faf 100644 --- a/games.py +++ b/games.py @@ -102,10 +102,26 @@ class team(object): self.name = None self.lineup = [] self.lineup_position = 0 + self.rotation = [] self.pitcher = None self.score = 0 self.slogan = None + def swap_player(self, name): + if len(self.lineup) > 1: + for index in range(0,len(self.lineup)): + if self.lineup[index].name == name: + if self.add_pitcher(self.lineup[index]): + self.lineup.pop(index) + return True + if len(self.rotation) > 1: + for index in range(0,len(self.rotation)): + if self.rotation[index].name == name: + if self.add_lineup(self.rotation[index])[0]: + self.rotation.pop(index) + return True + return False + def add_lineup(self, new_player): if len(self.lineup) < 20: self.lineup.append(new_player) @@ -113,27 +129,48 @@ class team(object): else: return (False, "20 players in the lineup, maximum. We're being really generous here.") - def set_pitcher(self, new_player): - self.pitcher = new_player - return (True,) + def add_pitcher(self, new_player): + if len(self.rotation) < 8: + self.rotation.append(new_player) + return True + else: + return False + + def set_pitcher(self, rotation_slot = None, use_lineup = False): + temp_rotation = self.rotation.copy() + if use_lineup: + for batter in self.rotation: + temp_rotation.append(batter) + if rotation_slot is None: + self.pitcher = random.choice(temp_rotation) + else: + self.pitcher = temp_rotation[rotation_slot % len(temp_rotation)] def is_ready(self): - return (len(self.lineup) >= 1 and self.pitcher is not None) + return (len(self.lineup) >= 1 and len(self.rotation) > 0) def prepare_for_save(self): self.lineup_position = 0 self.score = 0 + if self.pitcher is not None and self.pitcher not in self.rotation: + self.rotation.append(self.pitcher) + self.pitcher = None for this_player in self.lineup: for stat in this_player.game_stats.keys(): this_player.game_stats[stat] = 0 + for this_player in self.rotation: + for stat in this_player.game_stats.keys(): + this_player.game_stats[stat] = 0 return True def finalize(self): if self.is_ready(): + if self.pitcher is None: + self.set_pitcher() while len(self.lineup) <= 4: - self.lineup.append(random.choice(self.lineup)) - return True - else: + self.lineup.append(random.choice(self.lineup)) + return self + else: return False @@ -619,20 +656,40 @@ def get_team(name): try: team_json = jsonpickle.decode(db.get_team(name)[0], keys=True, classes=team) if team_json is not None: + if team_json.pitcher is not None: #detects old-format teams, adds pitcher + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) return team_json return None + except AttributeError: + team_json.rotation = [] + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) + return team_json except: return None def get_team_and_owner(name): - #try: - counter, name, team_json_string, timestamp, owner_id = db.get_team(name, owner=True) - team_json = jsonpickle.decode(team_json_string, keys=True, classes=team) - if team_json is not None: + try: + counter, name, team_json_string, timestamp, owner_id = db.get_team(name, owner=True) + team_json = jsonpickle.decode(team_json_string, keys=True, classes=team) + if team_json is not None: + if team_json.pitcher is not None: #detects old-format teams, adds pitcher + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) + return (team_json, owner_id) + return None + except AttributeError: + team_json.rotation = [] + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) return (team_json, owner_id) - return None - #except: - #return None + except: + return None def save_team(this_team, user_id): try: @@ -643,6 +700,15 @@ def save_team(this_team, user_id): except: return None +def update_team(this_team): + try: + this_team.prepare_for_save() + team_json_string = jsonpickle.encode(this_team, keys=True) + db.update_team(this_team.name, team_json_string) + return True + except: + return None + def get_all_teams(): teams = [] for team_pickle in db.get_all_teams(): @@ -653,9 +719,23 @@ def get_all_teams(): def search_team(search_term): teams = [] for team_pickle in db.search_teams(search_term): - this_team = jsonpickle.decode(team_pickle[0], keys=True, classes=team) - teams.append(this_team) - return teams + team_json = jsonpickle.decode(team_pickle[0], keys=True, classes=team) + try: + if team_json.pitcher is not None: + if len(team_json.rotation) == 0: #detects old-format teams, adds pitcher + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) + except AttributeError: + team_json.rotation = [] + team_json.rotation.append(team_json.pitcher) + team_json.pitcher = None + update_team(team_json) + except: + return None + + teams.append(team_json) + return teams def base_string(base): if base == 1: diff --git a/leagues.py b/leagues.py new file mode 100644 index 0000000..bf44a2e --- /dev/null +++ b/leagues.py @@ -0,0 +1,19 @@ +import time, asyncio, jsonpickle +import database as db + + + + + +class league(object): + def __init__(self, name, subleagues_dic): + self.subleagues = {} #key: name, value: [divisions] + self.max_days + self.day = 1 + self.name = name + self.subleagues = subleagues_dic + +class division(object): + def __init__(self): + self.teams = {} #key: team name, value: {wins; losses; run diff} + diff --git a/main_controller.py b/main_controller.py index 9d995cc..0fdfb38 100644 --- a/main_controller.py +++ b/main_controller.py @@ -1,4 +1,4 @@ -import asyncio, time, datetime, games, json, threading, jinja2 +import asyncio, time, datetime, games, json, threading, jinja2, leagues from flask import Flask, url_for, Response, render_template, request, jsonify from flask_socketio import SocketIO, emit diff --git a/the-prestige.pyproj b/the-prestige.pyproj index c9f6968..351afa6 100644 --- a/the-prestige.pyproj +++ b/the-prestige.pyproj @@ -29,6 +29,9 @@ Code + + Code + Code diff --git a/the_prestige.py b/the_prestige.py index 89584a2..239595b 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -1,4 +1,4 @@ -import discord, json, math, os, roman, games, asyncio, random, main_controller, threading, time +import discord, json, math, os, roman, games, asyncio, random, main_controller, threading, time, leagues import database as db import onomancer as ono from flask import Flask @@ -169,7 +169,7 @@ class StartGameCommand(Command): return if team1 is not None and team2 is not None: - game = games.game(msg.author.name, team1, team2, length=innings) + game = games.game(msg.author.name, team1.finalize(), team2.finalize(), length=innings) channel = msg.channel await msg.delete() @@ -205,12 +205,19 @@ class SetupGameCommand(Command): class SaveTeamCommand(Command): name = "saveteam" - template = "m;saveteam [name] [slogan] [players]" + template = """m;saveteam + [name] + [slogan] + [lineup] + [rotation]""" + description = """Saves a team to the database allowing it to be used for games. Send this command at the top of a list, with entries separated by new lines (shift+enter in discord, or copy+paste from notepad). - the first line of the list is your team's name (cannot contain emoji). - the second line is your team's icon and slogan, this should begin with an emoji followed by a space, followed by a short slogan. + - the third line must be blank. - the next lines are your batters' names in the order you want them to appear in your lineup, lineups can contain any number of batters between 1 and 12. - - the final line is your pitcher's name. + - there must be another blank line between your batters and your pitchers. + - the final lines are your pitchers' names. if you did it correctly, you'll get a team embed with a prompt to confirm. hit the 👍 and it'll be saved.""" async def execute(self, msg, command): @@ -287,6 +294,31 @@ class CreditCommand(Command): async def execute(self, msg, command): await msg.channel.send("Our avatar was graciously provided to us, with permission, by @HetreaSky on Twitter.") +class SwapPlayerCommand(Command): + name = "swap" + template = """m;swap + [team name] + [player name]""" + description = "Swaps a player from lineup to rotation, or from rotation to lineup. Requires team ownership." + + async def execute(self, msg, command): + team_name = command.split("\n")[1].strip() + player_name = command.split("\n")[2].strip() + team, owner_id = games.get_team_and_owner(team_name) + if team is None: + await msg.channel.send("Can't find that team, boss. Typo?") + return + elif owner_id != msg.author.id or msg.author.id not in config()["owners"]: + await msg.channel.send("You're not authorized to mess with this team. Sorry, boss.") + return + elif not team.swap_player(player_name): + await msg.channel.send("Either we can't find that player, or they're your last member of that side of the roster. Can't field an empty lineup, chief.") + return + else: + await msg.channel.send(embed=build_team_embed(team)) + games.update_team(team) + await msg.channel.send("Paperwork signed, stamped, and copied.") + class HelpCommand(Command): name = "help" template = "m;help [command]" @@ -353,6 +385,7 @@ commands = [ #SetupGameCommand(), SaveTeamCommand(), ImportCommand(), + SwapPlayerCommand(), DeleteTeamCommand(), ShowTeamCommand(), ShowAllTeamsCommand(), @@ -660,7 +693,10 @@ def build_team_embed(team): for player in team.lineup: lineup_string += f"{player.name} {player.star_string('batting_stars')}\n" - embed.add_field(name="Pitcher:", value=f"{team.pitcher.name} {team.pitcher.star_string('pitching_stars')}", inline = False) + rotation_string = "" + for player in team.rotation: + rotation_string += f"{player.name} {player.star_string('pitching_stars')}\n" + embed.add_field(name="Rotation:", value=rotation_string, inline = False) embed.add_field(name="Lineup:", value=lineup_string, inline = False) embed.set_footer(text=team.slogan) return embed @@ -710,14 +746,22 @@ def team_from_message(command): roster = command.split("\n",1)[1].split("\n") newteam.name = roster[0] #first line is team name newteam.slogan = roster[1] #second line is slogan - for rosternum in range(2,len(roster)-1): + if not roster[2].strip() == "": + raise CommandError("The third line should be blank. It wasn't, so just in case, we've not done anything on our end.") + pitchernum = len(roster)-2 + for rosternum in range(3,len(roster)-1): if roster[rosternum] != "": if len(roster[rosternum]) > 70: raise CommandError(f"{roster[rosternum]} is too long, chief. 70 or less.") newteam.add_lineup(games.player(ono.get_stats(roster[rosternum].rstrip()))) - if len(roster[len(roster)-1]) > 70: - raise CommandError(f"{roster[len(roster)-1]} is too long, chief. 70 or less.") - newteam.set_pitcher(games.player(ono.get_stats(roster[len(roster)-1].rstrip()))) #last line is pitcher name + else: + pitchernum = rosternum + 1 + break + + for rosternum in range(pitchernum, len(roster)): + if len(roster[rosternum]) > 70: + raise CommandError(f"{roster[len(roster)-1]} is too long, chief. 70 or less.") + newteam.add_pitcher(games.player(ono.get_stats(roster[rosternum].rstrip()))) if len(newteam.name) > 30: raise CommandError("Team names have to be less than 30 characters! Try again.")