diff --git a/src/werewolf_bot.py b/src/werewolf_bot.py index 7ee894e..c61c82e 100644 --- a/src/werewolf_bot.py +++ b/src/werewolf_bot.py @@ -13,152 +13,74 @@ if TOKEN is None: print("Missing discord token!") exit(1) - -PREFIX = '$w ' -bot = commands.Bot(command_prefix=commands.when_mentioned_or(PREFIX)) -bot.remove_command('help') +bot = commands.Bot(command_prefix=commands.when_mentioned_or('$werewolf ')) @bot.event async def on_ready(): - await bot.change_presence(status=discord.Status.online, activity=discord.Game('One Night Ultimate Werewolf')) + await bot.change_presence(status=discord.Status.idle, activity=discord.Game('One Night Ultimate Werewolf')) print('We have logged in as {0.user}'.format(bot)) -@bot.command() -async def help(ctx): - embed = discord.Embed(title="How to play?", description="You will need to set up the game and its information in a channel and start the game there. Afterwards the player mainly interact with the bot in DM.", color=0x00ffff) - embed.set_author(name="With this bot you can play One Night Ultimate Werewolf") - # embed.set_thumbnail(url="https://images-na.ssl-images-amazon.com/images/I/717GrDtFKCL._AC_SL1000_.jpg") - embed.add_field(name="$w game setup", value="Make this channel playable.", inline=False) - embed.add_field(name="$w game players", value="Set mentioned users as players", inline=False) - embed.add_field(name="$w game roles", value="Set the roles to play with", inline=False) - embed.add_field(name="$w game start", value="Play one round", inline=False) - embed.set_footer(text="Have fun!") - await ctx.send(embed=embed) +@bot.event +async def on_message(message): + if message.author == bot.user: + return + await bot.process_commands(message) -async def send_embed(ctx, desc, color): - await ctx.send(embed=discord.Embed(description=desc, color=color)) - - -async def send_friendly(ctx, desc): - await send_embed(ctx, desc, 0x00ff00) - - -async def send_wrong(ctx, desc): - await send_embed(ctx, desc, 0xff8000) - - -# game commands - -game_instances = {} - - -@bot.group() +@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 send_wrong(ctx, 'Invalid sub command passed...') + await bot.say('Invalid sub command passed...') -@game.command() -async def setup(ctx): - if ctx.channel in game_instances: - await send_wrong(ctx, "Game already setup in this channel") - else: - game_instances[ctx.channel] = Werewolf_Game(bot, ctx.channel) - await send_friendly(ctx, "This channel can now play Werewolf") - - -def game_running(command): - @functools.wraps(command) - async def wrapper(ctx): - if ctx.channel not in game_instances: - await send_wrong(ctx, f"No game setup yet. Use {PREFIX}game setup") - elif game_instances[ctx.channel].running: - await send_wrong(ctx, "Sorry! A game is already running") - else: - await command(ctx) - return wrapper - - -def error_handling(command): - @functools.wraps(command) - async def wrapper(ctx): - try: - await command(ctx) - except ValueError as error: - await send_wrong(ctx, str(error)) - except asyncio.TimeoutError: - await send_wrong(ctx, "Error: I got bored waiting for your input") - return wrapper - - -@game.command() -@game_running -@error_handling +@game.command(help="start werewolf game", description="Start One Night Ultimate Werewolf game.") async def start(ctx): - await game_instances[ctx.channel].game() + if werewolf_game.running: + await ctx.message.channel.send("Sorry! A game is already running") + return + + werewolf_game.running = True + werewolf_game.set_channel(ctx.message.channel) + + await werewolf_game.game() -@game.command() -@game_running -@error_handling -async def players(ctx): - await game_instances[ctx.channel].set_players(ctx.message) - - -@game.command() -@game_running -@error_handling -async def roles(ctx): - await game_instances[ctx.channel].set_roles(ctx.message.content.split()[3:]) # exclude commands - -# ONLY FOR TESTING -@game.command() -@game_running -@error_handling -async def vote(ctx): - await game_instances[ctx.channel].vote() - - -# smaller commands - -@bot.command() +@bot.command(help="greets you", description="This just says hello back to the message author.") async def hello(ctx): - await send_friendly(ctx, f"Hello {ctx.message.author.name} :wave:") + await ctx.message.channel.send(f"Hello {ctx.message.author.name} :wave:") -@bot.command() +@bot.command(help="test bot responsiveness", description="This is a debug function to see if the bot listens to a command.") async def ping(ctx): print("pong") - await send_friendly(ctx, "pong") - - -# developer commands + await ctx.send("pong") def developer(command): @functools.wraps(command) async def wrapper(ctx): DEV_ID = 461892912821698562 - if ctx.author.id == DEV_ID: + if ctx.message.author.id == DEV_ID: await command(ctx) else: - await send_wrong(ctx, "This command is not for you!") + await ctx.send("This command is not for you!") return wrapper -@bot.command() +@bot.command(help="not for you", description="Shut down the bot.") @developer async def logout(ctx): await bot.logout() -@bot.command() +@bot.command(help="debug") @developer 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 8abf581..e9e5d81 100644 --- a/src/werewolf_game.py +++ b/src/werewolf_game.py @@ -1,108 +1,131 @@ from random import shuffle import asyncio -import discord -from werewolf_roles import Role, Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Tanner, Hunter, No_role +from werewolf_roles import Role, Werewolf, Minion, Tanner, Hunter from werewolf_players import Player, No_player class Game: - def __init__(self, bot, channel): + def __init__(self, bot): self.running = False self.bot = bot - self.channel = channel self.player_list = [] - self.role_list = [] + self.role_list = Role.role_set + + def set_channel(self, channel): + self.channel = channel async def send(self, message): - await self.channel.send(embed=discord.Embed(description=message, color=0x00ffff)) + await self.channel.send(message) - async def for_all_player(self, call): - await asyncio.gather(*[call(p) for p in self.player_list]) + async def receive(self, command): + def check(msg): + return msg.channel == self.channel and msg.content.startswith(command) - async def set_players(self, msg): - self.player_list = [await Player.make(mem, self) for mem in msg.mentions] - await self.send(f"Players: {', '.join(p.name() for p in self.player_list)}") # send confirmation - - async def set_roles(self, suggestions): - self.role_list = [Role.match(r) for r in suggestions] # raises ValueError - await self.send(f"Roles: {', '.join(r.name() for r in self.role_list)}") # send confirmation - - 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") + return await self.bot.wait_for('message', check=check) def setup(self): - self.role = dict() - for r in Role.__subclasses__(): - if r not in [Werewolf, Mason, No_role]: - r(self) - self.role[Werewolf] = [] - self.role[Mason] = [] - self.voting_list = self.player_list + [No_player()] - for c in self.voting_list: - c.tally = 0 - c.won = c.dead = False + 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))) + + # 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") + + # send confirmation + await self.send("Roles: " + ", ".join(r.name() for r in self.role_list)) def distribute_roles(self): shuffle(self.role_list) for i in range(len(self.player_list)): - self.role_list[i](self, self.player_list[i]) + self.player_list[i].setRole(self.role_list[i]) + self.role_list[i].setPlayer(self.player_list[i]) + self.middle_card = self.role_list[-3:] + self.active_role = sorted(self.role_list[:-3], key=lambda x: x.order) async def start_night(self): - await self.for_all_player(lambda p: p.send_normal("*The night has begun*")) + await asyncio.gather(*[p.send("The night has begun") for p in self.player_list]) async def send_role(self): - await self.for_all_player(lambda p: p.send_info(f"Your role: **{p.night_role.name()}**")) + await asyncio.gather(*[p.send("Your role: " + p.night_role.name()) for p in self.player_list]) async def night_phases(self): - await asyncio.gather(*[self.role[r].query() for r in [Doppelganger, Seer, Robber, Troublemaker, Drunk]]) # slow - await self.role[Doppelganger].send_copy_info() - await self.role[Doppelganger].simulate() # slow - await asyncio.gather(*[w.phase() for w in self.role[Werewolf]]) # slow - await asyncio.gather(*[w.send_info() for w in [self.role[Minion]] + self.role[Mason] + [self.role[Seer]]]) - await self.role[Robber].simulate() - await self.role[Robber].send_info() - await self.role[Troublemaker].simulate() - await self.role[Drunk].simulate() - await self.role[Insomniac].send_info() - await self.role[Doppelganger].insomniac() + await asyncio.gather(*[r.phase1() for r in self.active_role]) + await asyncio.gather(*[r.phase2() for r in self.active_role]) + await asyncio.gather(*[r.phase3() for r in self.active_role]) + await asyncio.gather(*[r.phase4() for r in self.active_role]) + await asyncio.gather(*[r.phase5() for r in self.active_role]) async def start_day(self): await self.send("The day has started") - async def vote(self): + async def vote(self, options): # vote - # replace with dm: await self.receive('$vote') + await self.receive('$vote') await self.send("Vote in DM") - await self.for_all_player(lambda p: p.cast_vote("Who do you want to kill?", self.voting_list)) + await asyncio.gather(*[p.cast_vote(options) for p in self.player_list]) + + await self.send("Votes\n\n" + '\n'.join(str(p) + " :arrow_right: " + str(p.vote) for p in self.player_list)) + + def tally(self, options): + for o in options: + o.tally = 0 - def tally(self): for p in self.player_list: p.vote.tally += 1 - def who_dead(self): - maxi = max(c.tally for c in self.voting_list) + def who_dead(self, options): + + maxi = max(o.tally for o in options) dead = [p for p in self.player_list if p.tally >= maxi] for d in dead: d.dead = True - if d.day_role.is_role(Hunter): + if isinstance(d.day_role.copy, Hunter): dead.append(d.vote) + return dead def who_won(self, dead): no_dead = (len(dead) == 0) - tanner_dead = any(d.day_role.is_role(Tanner) for d in dead) - werewolf_dead = any(d.day_role.is_role(Werewolf) for d in dead) - werewolf_in_game = any(p.day_role.is_role(Werewolf) for p in self.player_list) - minion_dead = any(d.day_role.is_role(Minion) for d in dead) - minion_in_game = any(p.day_role.is_role(Minion) for p in self.player_list) + tanner_dead = any(isinstance(d.day_role.copy, Tanner) for d in dead) + werewolf_dead = any(isinstance(d.day_role.copy, Werewolf) for d in dead) + werewolf_in_game = any(isinstance(p.day_role.copy, Werewolf) for p in self.player_list) + minion_dead = any(isinstance(d.day_role.copy, Minion) for d in dead) + minion_in_game = any(isinstance(p.day_role.copy, Minion) for p in self.player_list) werewolf_won = False village_won = False @@ -134,42 +157,37 @@ class Game: if minion_in_game: werewolf_won = True - for p in self.player_list: - if p.day_role.is_role(Werewolf) or p.day_role.is_role(Minion): - p.won = werewolf_won - elif p.day_role.is_role(Tanner): - p.won = p.dead - else: - p.won = village_won - return werewolf_won, village_won, tanner_won, dead async def result(self, werewolf_won, village_won, tanner_won, dead): if werewolf_won: - winnning = ["Werewolves won!"] + await self.send("Werewolves won!") + if village_won: - winnning = ["Village won!"] - if tanner_won: - winnning.append(f"{sum(1 for d in dead if d.day_role.is_role(Tanner))} tanner won") + await self.send("Village won!") - embed = discord.Embed(title=' and '.join(winnning), color=0x00ffff) - for p in self.player_list: - won_emoji = ":trophy:" if p.won else ":frowning2:" - dead_emoji = ":skull:" if p.dead else ":no_mouth:" - embed.add_field(name=str(p), value=f"{won_emoji} {dead_emoji} {p.tally}:ballot_box: role: {str(p.day_role)} (was: {str(p.night_role)}) :point_right: {str(p.vote)}", inline=False) - embed.add_field(name="Middle cards", value=', '.join(r.name() for r in self.middle_card), inline=False) + for d in dead: + if isinstance(d.day_role.copy, Tanner): + await self.send(str(d) + " won a tanner") - await self.channel.send(embed=embed) + await self.send(":skull: " + ', '.join(str(d) for d in dead)) + await self.send('\n'.join(":ballot_box " + str(p.tally) + " votes for " + str(p) + " who is " + str(p.day_role) + " (was " + str(p.night_role) + ") " for p in self.player_list)) + await self.send("Middle cards: " + ', '.join(str(r) for r in self.middle_card)) + + # debug + await self.send("Success") def end(self): self.running = False async def game(self): + try: - self.check() - self.running = True + self.setup() + await self.set_players() + await self.set_roles() self.distribute_roles() await self.start_night() await self.send_role() @@ -179,10 +197,15 @@ class Game: await self.start_day() # discussion timer - await self.vote() - self.tally() - await self.result(*self.who_won(self.who_dead())) + options = self.player_list + [No_player(self)] + await self.vote(options) + self.tally(options) + await self.result(*self.who_won(self.who_dead(options))) - await self.send("Round ended") + except ValueError as error: + await self.send(error) + except asyncio.TimeoutError: + await self.send("Error: I got bored waiting for your input") finally: self.end() + await self.send("Game ended") diff --git a/src/werewolf_players.py b/src/werewolf_players.py index 5c7f89e..2d88af0 100644 --- a/src/werewolf_players.py +++ b/src/werewolf_players.py @@ -1,4 +1,4 @@ -import discord +from werewolf_roles import No_role class Player: @@ -11,77 +11,49 @@ class Player: p.game = game return p + def swap(self, player_B): + self.day_role, player_B.day_role = player_B.day_role, self.day_role + def setRole(self, role): - self.day_role = self.night_role = role + self.night_role = role + self.day_role = role def name(self): return self.member.name - def __str__(self): + def __repr__(self): return self.name() - def swap(self, player_B): - self.day_role, player_B.day_role = player_B.day_role, self.day_role - def other(self): return [p for p in self.game.player_list if p != self] - async def send_normal(self, message): + async def send(self, message): await self.dm.send(message) - async def send_embed(self, desc, color): - await self.dm.send(embed=discord.Embed(description=desc, color=color)) + async def ask_choice(self, options): + await self.send('\n'.join("(" + str(i) + ") " + str(options[i]) for i in range(len(options)))) - async def send_wrong(self, message): - await self.send_embed(message, 0xff8000) + async def receive_choice(self, options): + def check(choice): + return choice.channel == self.dm and choice.content.isdigit() and 0 <= int(choice.content) < len(options) - async def send_confirmation(self, message): - await self.send_embed(message, 0x00ff00) + return int((await self.game.bot.wait_for('message', timeout=30.0, check=check)).content) - async def send_info(self, message): - await self.send_embed(message, 0x00ffff) + async def get_choice(self, options): + await self.ask_choice(options) + return await self.receive_choice(options) - async def ask_choice(self, question, options): - text = f"{question}\n" + f"{'='*len(question)}\n\n" + '\n'.join(f"[{str(i)}]({str(options[i])})" for i in range(len(options))) - await self.dm.send(f"```md\n{text}```") - - def check_num(self, choice, N): - if not choice.isdigit(): - raise ValueError(f"Your choice {choice} is not a number") - if not 0 <= int(choice) < N: - raise ValueError(f"Your choice {choice} is not in range 0 - {N-1}") - - async def receive_choice(self, options, n_ans=1): - while True: - def check(choice): - return choice.channel == self.dm and choice.author == self.member - choice = (await self.game.bot.wait_for('message', timeout=30.0, check=check)).content.split() - - if not len(choice) == n_ans: - await self.send_wrong(f"Please give {n_ans} numbers not {len(choice)}") - continue - try: - for c in choice: - self.check_num(c, len(options)) - except ValueError as error: - await self.send_wrong(str(error)) - continue - - await self.send_confirmation(f"Received: {', '.join(choice)}") - return [int(c) for c in choice] - - async def get_choice(self, question, options): - await self.ask_choice(question, options) - return (await self.receive_choice(options))[0] - - async def get_double_choice(self, question, options): - await self.ask_choice(question, options) - return await self.receive_choice(options, 2) - - async def cast_vote(self, question, options): - self.vote = options[await self.get_choice(question, options)] + async def cast_vote(self, options): + self.vote = options[await self.get_choice(options)] class No_player(Player): + + def __init__(self): + self.day_role = No_role() + 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 0c5b213..5185634 100644 --- a/src/werewolf_roles.py +++ b/src/werewolf_roles.py @@ -1,37 +1,32 @@ -import functools -from werewolf_players import No_player - - class Role: - def __init__(self, game, player=No_player()): + + def __init__(self, game): self.game = game + self.copy = self + + def setPlayer(self, player): self.player = player - self.player.setRole(self) - self.add_yourself() - def add_yourself(self): - self.game.role[type(self)] = self + async def phase1(self): # query stuff + doppelganger simulation + pass - async def send_role_list(self, cls): - await self.player.send_info(f"{cls.name()}: {', '.join(r.player.name() for r in self.game.role[cls])}") + async def phase2(self): # werewolf stuff + seer info + pass - def is_role(self, cls): - return isinstance(self, cls) + async def phase3(self): # robber simulation & info + pass + + async def phase4(self): # troublemaker simulation + pass + + async def phase5(self): # mostly sending info + drunk simulation + pass @staticmethod - def match(message): - for role_class in Role.__subclasses__(): + def match(message, game): + for role_class in Role.role_set: if message.casefold() == role_class.name(): - return role_class - raise ValueError(f"Invalid role: {message}") - - @staticmethod - def no_player(func): - @functools.wraps(func) - async def wrapper(self, *args, **kwargs): - if not isinstance(self.player, No_player): - return await func(self, *args, **kwargs) - return wrapper + return role_class(game) @classmethod def name(cls): @@ -42,138 +37,130 @@ class Role: class Doppelganger(Role): - @Role.no_player - async def query(self): - self.choice = await self.player.get_choice("Which player role do you want to copy?", self.player.other()) - - @Role.no_player - async def send_copy_info(self): - self.copy_role = type(self.player.other()[self.choice].day_role) - await self.send_info(f"You copied: {self.copy_role}") - - @Role.no_player - async def simulate(self): - if self.copy_role in [Werewolf, Mason]: - self.copy_role.add_yourself(self) - if self.copy_role == Werewolf: - await self.copy_role.phase(self) - if self.copy_role in [Mason, Minion]: - await self.copy_role.send_info(self) - - if self.copy_role in [Seer, Robber, Troublemaker, Drunk]: - await self.copy_role.query(self) - if self.copy_role in [Robber, Troublemaker, Drunk]: - self.copy_role.simulate(self) - if self.copy_role in [Seer, Robber]: - await self.copy_role.send_info(self) - - @Role.no_player - async def insomniac(self): - if self.copy_role == Insomniac: - self.copy_role.send_info(self) - - def is_role(self, cls): - return self.copy_role == cls + order = 1 class Werewolf(Role): - def add_yourself(self): - self.game.role[Werewolf].append(self) + order = 2 - @Role.no_player - async def phase(self): - if len(self.game.role[Werewolf]) >= 2: - await self.send_role_list(Werewolf) + def setPlayer(self, player): + super().setPlayer(player) + self.game.werewolf_list.append(player) + + async def phase2(self): + if len(self.game.werewolf_list) >= 2: + await self.player.send("Werewolves: " + str(self.game.werewolf_list)) else: - await self.player.send_info("You are the only werewolf") - self.choice = await self.player.get_choice("Which card in the middle do you want to look at?", ["left", "middle", "right"]) # 0, 1, 2 + await self.player.send("You are the only werewolf") + await self.player.send("Which card in the middle do you want to look at?") + self.choice = await self.player.get_choice(["left", "middle", "right"]) - await self.player.send_info(f"A card in the middle is: {self.game.middle_card[self.choice].name()}") + await self.player.send("A card in the middle is: " + self.game.middle_card[self.choice].name()) class Minion(Role): - @Role.no_player - async def send_info(self): - if len(self.game.role[Werewolf]) == 0: - await self.player.send_info("There were no werewolves, so you need to kill a villager!") + order = 3 + + async def phase2(self): + if len(self.game.werewolf_list) == 0: + await self.player.send("There were no werewolves so you became one") else: - await self.send_role_list(Werewolf) + await self.player.send("Werewolves: " + str(self.game.werewolf_list)) class Mason(Role): - def add_yourself(self): - self.game.role[Mason].append(self) + order = 4 - @Role.no_player - async def send_info(self): - await self.send_role_list(Mason) + def setPlayer(self, player): + super().setPlayer(player) + self.game.mason_list.append(player) + + async def phase2(self): + await self.player.send("Mason " + str(self.game.mason_list)) class Seer(Role): - @Role.no_player - async def query(self): - self.choice = await self.player.get_choice("Which 1 player card or 2 middle cards do you want to look at?", self.player.other() + ["left & middle", "middle & right", "left & right"]) + order = 5 - @Role.no_player - async def send_info(self): + async def phase1(self): + await self.player.send("Which 1 player card or 2 middle cards do you want to look at?") + self.choice = await self.player.get_choice(self.player.other() + ["left & middle", "middle & right", "left & right"]) + + async def phase2(self): if self.choice < len(self.player.other()): - await self.player.send_info(self.player.other()[self.choice].night_role) + await self.player.send(self.player.other()[self.choice].night_role) else: - a, b = [(0, 1), (1, 2), (0, 2)][self.choice - len(self.player.other())] - await self.player.send_info(f"{self.game.middle_card[a]} {self.game.middle_card[b]}") + self.choice -= len(self.player.other()) + if self.choice == 0: + a, b = 0, 1 + elif self.choice == 1: + a, b = 1, 2 + else: + a, b = 0, 2 + + await self.player.send(str(self.game.middle_card[a]) + " " + str(self.game.middle_card[b])) class Robber(Role): - @Role.no_player - async def query(self): - self.choice = await self.player.get_choice("Which player do you want to rob?", self.player.other()) + order = 6 - @Role.no_player - def simulate(self): + async def phase1(self): + await self.player.send("Which player do you want to rob?") + self.choice = await self.player.get_choice(self.player.other()) + + async def phase3(self): self.player.swap(self.player.other()[self.choice]) - - @Role.no_player - async def send_info(self): - await self.player.send_info(f"You robbed: {self.player.day_role}") + await self.player.send("You robbed: " + str(self.player.day_role)) class Troublemaker(Role): - @Role.no_player - async def query(self): - self.A, self.B = await self.player.get_double_choice("Who do you want to exchange? (send two numbers)", self.player.other()) + order = 7 - @Role.no_player - def simulate(self): + async def phase1(self): + await self.player.send("Who do you want to exchange? (send two separate numbers)") + self.A = await self.player.get_choice(self.player.other()) + self.B = await self.player.get_choice(self.player.other()) + + async def phase4(self): self.player.other()[self.A].swap(self.player.other()[self.B]) + # receive conformation + await self.player.send("Received " + str(self.A) + " " + str(self.B)) class Drunk(Role): - @Role.no_player - async def query(self): - self.choice = await self.player.get_choice("Which card from the middle do you want to take?", ["left", "middle", "right"]) + order = 8 - @Role.no_player - def simulate(self): - self.player.day_role, self.game.middle_card[self.choice] = self.game.middle_card[self.choice], self.player.day_role # swap + async def phase1(self): + await self.player.send("Which card from the middle do you want to take?") + self.choice = await self.player.get_choice(["left", "middle", "right"]) + + async def phase5(self): + self.player.day_role, self.game.middle_card[self.choice] = self.game.middle_card[self.choice], self.player.day_role + # receive conformation + await self.player.send("Received " + str(self.choice)) class Insomniac(Role): - @Role.no_player - async def send_info(self): - await self.player.send_info(f"You are now: {self.player.day_role}") + order = 9 + + async def phase5(self): + await self.player.send("You are now: " + str(self.player.day_role)) -class Villager(Role): - pass +class Villiager(Role): + order = 10 class Tanner(Role): - pass + order = 11 class Hunter(Role): - pass + order = 12 class No_role(Role): - pass + order = 1000 + + +Role.role_set = [Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Villiager, Tanner, Hunter]