diff --git a/src/werewolf_bot.py b/src/werewolf_bot.py index c61c82e..7ee894e 100644 --- a/src/werewolf_bot.py +++ b/src/werewolf_bot.py @@ -13,74 +13,152 @@ 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.remove_command('help') @bot.event async def on_ready(): - await bot.change_presence(status=discord.Status.idle, activity=discord.Game('One Night Ultimate Werewolf')) + await bot.change_presence(status=discord.Status.online, activity=discord.Game('One Night Ultimate Werewolf')) 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) +@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.group(help="werewolf game", description="Prefix for the One Night Ultimate Werewolf commands.") +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() async def game(ctx): if ctx.invoked_subcommand is None: - await bot.say('Invalid sub command passed...') + await send_wrong(ctx, 'Invalid sub command passed...') -@game.command(help="start werewolf game", description="Start One Night Ultimate Werewolf game.") +@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 async def start(ctx): - 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() + await game_instances[ctx.channel].game() -@bot.command(help="greets you", description="This just says hello back to the message author.") +@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() async def hello(ctx): - await ctx.message.channel.send(f"Hello {ctx.message.author.name} :wave:") + await send_friendly(ctx, 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.") +@bot.command() async def ping(ctx): print("pong") - await ctx.send("pong") + await send_friendly(ctx, "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!") + await send_wrong(ctx, "This command is not for you!") return wrapper -@bot.command(help="not for you", description="Shut down the bot.") +@bot.command() @developer async def logout(ctx): await bot.logout() -@bot.command(help="debug") +@bot.command() @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 e9e5d81..8abf581 100644 --- a/src/werewolf_game.py +++ b/src/werewolf_game.py @@ -1,131 +1,108 @@ from random import shuffle import asyncio -from werewolf_roles import Role, Werewolf, Minion, Tanner, Hunter +import discord +from werewolf_roles import Role, Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Tanner, Hunter, No_role 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) + await self.channel.send(embed=discord.Embed(description=message, color=0x00ffff)) - async def receive(self, command): - def check(msg): - return msg.channel == self.channel and msg.content.startswith(command) + async def for_all_player(self, call): + await asyncio.gather(*[call(p) for p in self.player_list]) - return await self.bot.wait_for('message', check=check) + 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") 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))) - - # 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)) + 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 def distribute_roles(self): shuffle(self.role_list) for i in range(len(self.player_list)): - self.player_list[i].setRole(self.role_list[i]) - self.role_list[i].setPlayer(self.player_list[i]) - + self.role_list[i](self, 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 asyncio.gather(*[p.send("The night has begun") for p in self.player_list]) + await self.for_all_player(lambda p: p.send_normal("*The night has begun*")) async def send_role(self): - await asyncio.gather(*[p.send("Your role: " + p.night_role.name()) for p in self.player_list]) + await self.for_all_player(lambda p: p.send_info(f"Your role: **{p.night_role.name()}**")) async def night_phases(self): - 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]) + 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() async def start_day(self): await self.send("The day has started") - async def vote(self, options): + async def vote(self): # 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]) - - 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 + await self.for_all_player(lambda p: p.cast_vote("Who do you want to kill?", self.voting_list)) + def tally(self): for p in self.player_list: p.vote.tally += 1 - def who_dead(self, options): - - maxi = max(o.tally for o in options) + def who_dead(self): + maxi = max(c.tally for c in self.voting_list) dead = [p for p in self.player_list if p.tally >= maxi] for d in dead: d.dead = True - if isinstance(d.day_role.copy, Hunter): + if d.day_role.is_role(Hunter): dead.append(d.vote) - return dead def who_won(self, dead): no_dead = (len(dead) == 0) - 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) + 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) werewolf_won = False village_won = False @@ -157,37 +134,42 @@ 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: - await self.send("Werewolves won!") - + winnning = ["Werewolves won!"] if village_won: - await self.send("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") - for d in dead: - if isinstance(d.day_role.copy, Tanner): - await self.send(str(d) + " won a tanner") + 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) - 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") + await self.channel.send(embed=embed) 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() @@ -197,15 +179,10 @@ class Game: await self.start_day() # discussion timer - 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.vote() + self.tally() + await self.result(*self.who_won(self.who_dead())) - except ValueError as error: - await self.send(error) - except asyncio.TimeoutError: - await self.send("Error: I got bored waiting for your input") + await self.send("Round ended") finally: self.end() - await self.send("Game ended") diff --git a/src/werewolf_players.py b/src/werewolf_players.py index 2d88af0..5c7f89e 100644 --- a/src/werewolf_players.py +++ b/src/werewolf_players.py @@ -1,4 +1,4 @@ -from werewolf_roles import No_role +import discord class Player: @@ -11,49 +11,77 @@ 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.night_role = role - self.day_role = role + self.day_role = self.night_role = role def name(self): return self.member.name - def __repr__(self): + def __str__(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(self, message): + async def send_normal(self, message): await self.dm.send(message) - 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_embed(self, desc, color): + await self.dm.send(embed=discord.Embed(description=desc, color=color)) - 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_wrong(self, message): + await self.send_embed(message, 0xff8000) - return int((await self.game.bot.wait_for('message', timeout=30.0, check=check)).content) + async def send_confirmation(self, message): + await self.send_embed(message, 0x00ff00) - async def get_choice(self, options): - await self.ask_choice(options) - return await self.receive_choice(options) + async def send_info(self, message): + await self.send_embed(message, 0x00ffff) - async def cast_vote(self, options): - self.vote = options[await self.get_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)] 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 5185634..0c5b213 100644 --- a/src/werewolf_roles.py +++ b/src/werewolf_roles.py @@ -1,32 +1,37 @@ +import functools +from werewolf_players import No_player + + class Role: - - def __init__(self, game): + def __init__(self, game, player=No_player()): self.game = game - self.copy = self - - def setPlayer(self, player): self.player = player + self.player.setRole(self) + self.add_yourself() - async def phase1(self): # query stuff + doppelganger simulation - pass + def add_yourself(self): + self.game.role[type(self)] = self - async def phase2(self): # werewolf stuff + seer info - 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 phase3(self): # robber simulation & info - pass - - async def phase4(self): # troublemaker simulation - pass - - async def phase5(self): # mostly sending info + drunk simulation - pass + def is_role(self, cls): + return isinstance(self, cls) @staticmethod - def match(message, game): - for role_class in Role.role_set: + def match(message): + for role_class in Role.__subclasses__(): if message.casefold() == role_class.name(): - return role_class(game) + 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 @classmethod def name(cls): @@ -37,130 +42,138 @@ class Role: class Doppelganger(Role): - order = 1 + @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 class Werewolf(Role): - order = 2 + def add_yourself(self): + self.game.role[Werewolf].append(self) - 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)) + @Role.no_player + async def phase(self): + if len(self.game.role[Werewolf]) >= 2: + await self.send_role_list(Werewolf) else: - 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("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("A card in the middle is: " + self.game.middle_card[self.choice].name()) + await self.player.send_info(f"A card in the middle is: {self.game.middle_card[self.choice].name()}") class Minion(Role): - 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") + @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!") else: - await self.player.send("Werewolves: " + str(self.game.werewolf_list)) + await self.send_role_list(Werewolf) class Mason(Role): - order = 4 + def add_yourself(self): + self.game.role[Mason].append(self) - 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)) + @Role.no_player + async def send_info(self): + await self.send_role_list(Mason) class Seer(Role): - order = 5 + @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"]) - 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): + @Role.no_player + async def send_info(self): if self.choice < len(self.player.other()): - await self.player.send(self.player.other()[self.choice].night_role) + await self.player.send_info(self.player.other()[self.choice].night_role) else: - 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])) + 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]}") class Robber(Role): - order = 6 + @Role.no_player + async def query(self): + self.choice = await self.player.get_choice("Which player do you want to rob?", self.player.other()) - 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): + @Role.no_player + def simulate(self): self.player.swap(self.player.other()[self.choice]) - await self.player.send("You robbed: " + str(self.player.day_role)) + + @Role.no_player + async def send_info(self): + await self.player.send_info(f"You robbed: {self.player.day_role}") class Troublemaker(Role): - order = 7 + @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()) - 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): + @Role.no_player + def simulate(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): - order = 8 + @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"]) - 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)) + @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 class Insomniac(Role): - order = 9 - - async def phase5(self): - await self.player.send("You are now: " + str(self.player.day_role)) + @Role.no_player + async def send_info(self): + await self.player.send_info(f"You are now: {self.player.day_role}") -class Villiager(Role): - order = 10 +class Villager(Role): + pass class Tanner(Role): - order = 11 + pass class Hunter(Role): - order = 12 + pass class No_role(Role): - order = 1000 - - -Role.role_set = [Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Villiager, Tanner, Hunter] + pass