diff --git a/src/werewolf_bot.py b/src/werewolf_bot.py index c61c82e..20cf469 100644 --- a/src/werewolf_bot.py +++ b/src/werewolf_bot.py @@ -13,7 +13,8 @@ if TOKEN is None: print("Missing discord token!") exit(1) -bot = commands.Bot(command_prefix=commands.when_mentioned_or('$werewolf ')) +PREFIX = '$w ' +bot = commands.Bot(command_prefix=commands.when_mentioned_or(PREFIX)) @bot.event @@ -22,34 +23,70 @@ async def on_ready(): print('We have logged in as {0.user}'.format(bot)) -@bot.event -async def on_message(message): - if message.author == bot.user: - return - await bot.process_commands(message) +# game commands + +game_instances = {} @bot.group(help="werewolf game", description="Prefix for the One Night Ultimate Werewolf commands.") async def game(ctx): if ctx.invoked_subcommand is None: - await bot.say('Invalid sub command passed...') + await ctx.send('Invalid sub command passed...') @game.command(help="start werewolf game", description="Start One Night Ultimate Werewolf game.") +async def setup(ctx): + if ctx.channel in game_instances: + await ctx.send("Game already setup in this channel") + else: + game_instances[ctx.channel] = Werewolf_Game(bot, ctx.channel) + + +def game_running(command): + @functools.wraps(command) + async def wrapper(ctx): + if ctx.channel not in game_instances: + await ctx.send(f"No game setup yet. Use {PREFIX}game setup") + elif game_instances[ctx.channel].running: + await ctx.send("Sorry! A game is already running") + else: + await command(ctx) + return wrapper + + +@game.command(help="start a round", description="Play one round of One Night Ultimate Werewolf") +@game_running async def start(ctx): - if werewolf_game.running: - await ctx.message.channel.send("Sorry! A game is already running") - return + await game_instances[ctx.channel].game() - werewolf_game.running = True - werewolf_game.set_channel(ctx.message.channel) - await werewolf_game.game() +@game.command(help="set players", description="Set the players for the next round.") +@game_running +async def players(ctx): + await game_instances[ctx.channel].set_players(ctx.message) + + +@game.command(help="set roles", description="Set the roles for the next round.") +@game_running +async def roles(ctx): + try: + await game_instances[ctx.channel].set_roles(ctx.message.content.split()[3:]) + except ValueError as error: + await ctx.send(error) + +# ONLY FOR TESTING +@game.command() +@game_running +async def vote(ctx): + await game_instances[ctx.channel].vote() + + +# smaller commands @bot.command(help="greets you", description="This just says hello back to the message author.") async def hello(ctx): - await ctx.message.channel.send(f"Hello {ctx.message.author.name} :wave:") + await ctx.send(f"Hello {ctx.message.author.name} :wave:") @bot.command(help="test bot responsiveness", description="This is a debug function to see if the bot listens to a command.") @@ -58,11 +95,14 @@ async def ping(ctx): await ctx.send("pong") +# developer commands + + def developer(command): @functools.wraps(command) async def wrapper(ctx): DEV_ID = 461892912821698562 - if ctx.message.author.id == DEV_ID: + if ctx.author.id == DEV_ID: await command(ctx) else: await ctx.send("This command is not for you!") @@ -81,6 +121,4 @@ async def debug(ctx): print("DEBUG") print(ctx.message.author.id) - -werewolf_game = Werewolf_Game(bot) bot.run(TOKEN) diff --git a/src/werewolf_game.py b/src/werewolf_game.py index e9e5d81..c0b4df9 100644 --- a/src/werewolf_game.py +++ b/src/werewolf_game.py @@ -6,65 +6,40 @@ from werewolf_players import Player, No_player class Game: - def __init__(self, bot): + def __init__(self, bot, channel): self.running = False self.bot = bot - self.player_list = [] - self.role_list = Role.role_set - - def set_channel(self, channel): self.channel = channel + self.player_list = [] + self.role_list = [] async def send(self, message): await self.channel.send(message) - async def receive(self, command): - def check(msg): - return msg.channel == self.channel and msg.content.startswith(command) - - return await self.bot.wait_for('message', check=check) - - def setup(self): - self.werewolf_list = [] - self.mason_list = [] - - async def set_players(self): - - await self.send("Who is playing?") - msg = await self.receive('$players') - - # use info from last round otherwise - if not msg.content.startswith('$players last'): - self.player_list = [await Player.make(mem, self) for mem in msg.mentions] - - # check conditions - if not 0 <= len(self.player_list) <= 10: - raise ValueError("Invalid number of players: " + str(len(self.player_list))) + async def set_players(self, msg): + self.player_list = [await Player.make(mem, self) for mem in msg.mentions] # send confirmation await self.send("Players: " + ", ".join(p.name() for p in self.player_list)) - async def set_roles(self): - await self.send("With which roles do you want to play?") - msg = await self.receive('$roles') - - # use info from last round otherwise - if not msg.content.startswith('$roles last'): - tmp_role = [Role.match(r, self) for r in msg.content.split()[1:]] - - # invalid input - if None in tmp_role: - raise ValueError("Invalid list of roles: " + str(tmp_role)) - - self.role_list = tmp_role - - # check condition - if not len(self.role_list) == (len(self.player_list) + 3): - raise ValueError("Invalid number of roles: " + str(len(self.role_list)) + " with " + str(len(self.player_list)) + " players") + async def set_roles(self, suggestions): + self.role_list = [Role.match(r, self) for r in suggestions] # raises ValueError # send confirmation await self.send("Roles: " + ", ".join(r.name() for r in self.role_list)) + def check(self): + if not 0 <= len(self.player_list) <= 10: + raise ValueError(f"Invalid number of players: {len(self.player_list)}") + + if not len(self.role_list) == (len(self.player_list) + 3): + raise ValueError(f"Invalid number of roles: {len(self.role_list)} with {len(self.player_list)} players") + + def setup(self): + self.werewolf_list = [] + self.mason_list = [] + self.running = True + def distribute_roles(self): shuffle(self.role_list) for i in range(len(self.player_list)): @@ -93,7 +68,7 @@ class Game: async def vote(self, options): # vote - await self.receive('$vote') + # replace with dm: await self.receive('$vote') await self.send("Vote in DM") await asyncio.gather(*[p.cast_vote(options) for p in self.player_list]) @@ -185,9 +160,8 @@ class Game: try: + self.check() self.setup() - await self.set_players() - await self.set_roles() self.distribute_roles() await self.start_night() await self.send_role() @@ -208,4 +182,4 @@ class Game: await self.send("Error: I got bored waiting for your input") finally: self.end() - await self.send("Game ended") + await self.send("Round ended") diff --git a/src/werewolf_players.py b/src/werewolf_players.py index 2d88af0..cacef4a 100644 --- a/src/werewolf_players.py +++ b/src/werewolf_players.py @@ -21,7 +21,7 @@ class Player: def name(self): return self.member.name - def __repr__(self): + def __str__(self): return self.name() def other(self): @@ -54,6 +54,3 @@ class No_player(Player): def name(self): return "no one" - - def __str__(self): - return self.name() diff --git a/src/werewolf_roles.py b/src/werewolf_roles.py index 5185634..4e7173a 100644 --- a/src/werewolf_roles.py +++ b/src/werewolf_roles.py @@ -27,6 +27,7 @@ class Role: for role_class in Role.role_set: if message.casefold() == role_class.name(): return role_class(game) + raise ValueError(f"Invalid role: {message}") @classmethod def name(cls):