diff --git a/src/__pycache__/Role.cpython-37.pyc b/src/__pycache__/Role.cpython-37.pyc deleted file mode 100644 index d429ccc..0000000 Binary files a/src/__pycache__/Role.cpython-37.pyc and /dev/null differ diff --git a/src/__pycache__/werewolf_game.cpython-37.pyc b/src/__pycache__/werewolf_game.cpython-37.pyc deleted file mode 100644 index e8e5524..0000000 Binary files a/src/__pycache__/werewolf_game.cpython-37.pyc and /dev/null differ diff --git a/src/__pycache__/werewolf_players.cpython-37.pyc b/src/__pycache__/werewolf_players.cpython-37.pyc deleted file mode 100644 index bdcf3df..0000000 Binary files a/src/__pycache__/werewolf_players.cpython-37.pyc and /dev/null differ diff --git a/src/__pycache__/werewolf_roles.cpython-37.pyc b/src/__pycache__/werewolf_roles.cpython-37.pyc deleted file mode 100644 index 121e3a5..0000000 Binary files a/src/__pycache__/werewolf_roles.cpython-37.pyc and /dev/null differ diff --git a/src/werewolf_bot.py b/src/werewolf_bot.py deleted file mode 100644 index c52ab07..0000000 --- a/src/werewolf_bot.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import discord -import asyncio -from dotenv import load_dotenv - -from werewolf_game import Game as Werewolf_Game - - -load_dotenv() -TOKEN = os.getenv('DISCORD_TOKEN') -if TOKEN is None: - print("Missing discord token!") - exit(1) - -bot = discord.Client() - -@bot.event -async def on_ready(): - print('We have logged in as {0.user}'.format(bot)) - - - -async def hello(message): - print("Hello") - await message.channel.send('Hello!:regional_indicator_a:') - - print(message.mentions) - -@bot.event -async def on_message(message): - - global running - - if message.author == bot.user: - return - - - if message.content.startswith('$hello'): - await hello(message) - return - - - if message.content.startswith('$logout'): - await bot.logout() - return - - - if message.content.startswith('$werewolf'): - - # start (only one instance running) - - if werewolf_game.running: - await message.channel.send("Sorry! A game is already running") - return - - werewolf_game.running = True - werewolf_game.set_channel(message.channel) - - - await werewolf_game.game() - - return - -werewolf_game = Werewolf_Game(bot) -bot.run(TOKEN) diff --git a/src/werewolf_game.py b/src/werewolf_game.py deleted file mode 100644 index b01a931..0000000 --- a/src/werewolf_game.py +++ /dev/null @@ -1,218 +0,0 @@ -from random import shuffle -import asyncio -from werewolf_roles import Role, Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Villiager, Tanner, Hunter, No_role -from werewolf_players import Player, No_player - -class Game: - - def __init__(self, bot): - self.running = False - self.bot = bot - self.player_list = [] - self.role_list = Role.role_set - - - def set_channel(self, channel): - self.channel = channel - - - 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))) - - # 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.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) #necessary? - - - async def start_night(self): - await asyncio.gather( *[p.send("The night has begun") for p in self.player_list] ) - - async def send_role(self): - 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( *[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, options): - - # vote - 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 - - for p in self.player_list: - p.vote.tally += 1 - - 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 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(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 - tanner_won = False - - # could make it shorter using boolean algebra - if no_dead: - if werewolf_in_game: - werewolf_won = True - else: - village_won = True - else: - if tanner_dead: - tanner_won = True - - if werewolf_dead: - village_won = True - - else: - if werewolf_dead: - village_won = True - else: - if minion_dead: - if werewolf_in_game: - werewolf_won = True - else: - village_won = True - else: - if minion_in_game: - werewolf_won = True - - 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!") - - if village_won: - await self.send("Village won!") - - for d in dead: - if isinstance(d.day_role.copy, Tanner): - await self.send(str(d) + " won a tanner") - - 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.setup() - await self.set_players() - await self.set_roles() - self.distribute_roles() - await self.start_night() - await self.send_role() - - await self.night_phases() - - 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))) - - 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 deleted file mode 100644 index 9086772..0000000 --- a/src/werewolf_players.py +++ /dev/null @@ -1,56 +0,0 @@ -class Player: - - @staticmethod - async def make(member, game): - p = Player() - p.member = member - p.dm = member.dm_channel or await member.create_dm() - p.game = game - return p - - @staticmethod - def swap(player_A, player_B): - player_A.day_role, player_B.day_role = player_B.day_role, player_A.day_role - - def setRole(self, role): - self.night_role = role - self.day_role = role - - def name(self): - return self.member.name - - def __repr__(self): - return self.name() - - def other(self): - return [p for p in self.game.player_list if p != self] - - async def send(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 receive_choice(self, options): - def check(choice): - return choice.channel == self.dm and choice.content.isdigit() and 0 <= int(choice.content) < len(options) - - return int((await self.game.bot.wait_for('message', timeout=30.0, check = check)).content) - - async def get_choice(self, options): - await self.ask_choice(options) - return await self.receive_choice(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 deleted file mode 100644 index 8d108cd..0000000 --- a/src/werewolf_roles.py +++ /dev/null @@ -1,156 +0,0 @@ -class Role: - - def __init__(self, game): - self.game = game - self.copy = self - - def setPlayer(self, player): - self.player = player - - async def phase1(self): # query stuff + doppelganger simulation - pass - - async def phase2(self): # werewolf stuff + seer info - pass - - 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, game): - for role_class in Role.role_set: - if message.casefold() == role_class.name(): - return role_class(game) - - @classmethod - def name(cls): - return cls.__name__.casefold() - - def __str__(self): - return self.name() - -class Doppelganger(Role): - order = 1 - -class Werewolf(Role): - order = 2 - - 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("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("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") - else: - await self.player.send("Werewolves: " + str(self.game.werewolf_list)) - - -class Mason(Role): - order = 4 - - 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): - order = 5 - - 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(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])) - - -class Robber(Role): - order = 6 - - 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): - Player.swap(self.player, self.player.other()[self.choice]) - await self.player.send("You robbed: " + str(self.player.day_role)) - -class Troublemaker(Role): - order = 7 - - 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): - Player.swap(self.player.other()[self.A], self.player.other()[self.B]) - # receive conformation - await self.player.send("Received " + str(self.A) + " " + str(self.B)) - -class Drunk(Role): - order = 8 - - 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): - order = 9 - - async def phase5(self): - await self.player.send("You are now: " + str(self.player.day_role)) - -class Villiager(Role): - order = 10 - -class Tanner(Role): - order = 11 - -class Hunter(Role): - order = 12 - -class No_role(Role): - order = 1000 - -Role.role_set = [Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Villiager, Tanner, Hunter] \ No newline at end of file diff --git a/src/werewolve-bot-old.py b/src/werewolve-bot-old.py new file mode 100644 index 0000000..ba07ef9 --- /dev/null +++ b/src/werewolve-bot-old.py @@ -0,0 +1,381 @@ +import os +import discord +from enum import Enum +from random import shuffle +import asyncio +from dotenv import load_dotenv + +load_dotenv() +TOKEN = os.getenv('DISCORD_TOKEN') + +class Role(Enum): + doppelganger = 1 + werewolve = 2 + minion = 3 + mason = 4 + seer = 5 + robber = 6 + troublemaker = 7 + drunk = 8 + insomniac = 9 + villiager = 10 + tanner = 11 + hunter = 12 + +class Player: + + def __init__(self, member, role): + self.member = member + self.night_role = role + self.day_role = role + self.vote = -1 + self.tally = 0 + + async def create_dm(self): + self.dm = self.member.dm_channel or await self.member.create_dm() + + async def send(self, message): + await self.dm.send(message) + + async def sendRole(self): + await self.send("Your role: " + self.night_role.name) + + async def sendPoll(self): + await self.send(Player.poll_message) + + async def sendMiddle(self): + await self.send(Player.poll_middle) + + async def receiveChoice(self): + + global bot + + def check(vote): + + return vote.channel == self.dm and vote.content.isdigit() and 0 <= int(vote.content) < Player.size + + vote = await bot.wait_for('message', timeout=30.0, check = check) + await self.send("Received: " + vote.content) + + return int(vote.content) + + +bot = discord.Client() + +@bot.event +async def on_ready(): + print('We have logged in as {0.user}'.format(bot)) + + + +running = False + +async def hello(message): + print("Hello") + await message.channel.send('Hello!:regional_indicator_a:') + + def check(vote): + return vote.content in ["a", "b"] and vote.channel == message.channel + + vote = await bot.wait_for('message', timeout=10.0, check = check) + await message.channel.send("Received! " + vote.content) + +@bot.event +async def on_message(message): + + global running + + if message.author == bot.user: + return + + + if message.content.startswith('$hello'): + await hello(message) + return + + + if message.content.startswith('$logout'): + await bot.logout() + return + + if message.content.startswith('$werewolve'): + + # start (only one instance running) + + if running: + await message.channel.send("Sorry! A game is already running") + return + + + + + """ + if len(players) < 4: + await message.channel.send("To few players!") + return + + """ + + running = True + + + # setup + + members = [mem for mem in message.channel.members if not mem.bot] + + Player.size = len(members) + + + role_set = [Role.werewolve, Role.werewolve, Role.drunk, Role.insomniac, Role.seer, Role.robber, Role.hunter] + (Player.size-4)*[Role.villiager] + shuffle(role_set) + + players = [] + + + werewolve = [] + minion = None + mason = [] + seer = None + robber = None + troublemaker = None + drunk = None + insomniac = None + villiager = [] + tanner = None + hunter = None + + for i in range(Player.size): + + players.append(Player(members[i], role_set[i])) + await players[i].create_dm() + + + if role_set[i] == Role.werewolve: + werewolve.append(players[i]) + + elif role_set[i] == Role.mason: + mason.append(players[i]) + + elif role_set[i] == Role.seer: + seer = players[i] + + elif role_set[i] == Role.robber: + robber = players[i] + + elif role_set[i] == Role.troublemaker: + troublemaker = players[i] + + elif role_set[i] == Role.drunk: + drunk = players[i] + + elif role_set[i] == Role.insomniac: + insomniac = players[i] + + elif role_set[i] == Role.villiager: + villiager.append(players[i]) + + elif role_set[i] == Role.tanner: + tanner = players[i] + + elif role_set[i] == Role.hunter: + hunter = players[i] + + middle = role_set[-3:] + + + Player.poll_middle = "(0) left\n(1) middle\n(2) right" + + Player.poll_message = "" + for i in range(Player.size): + Player.poll_message += "(" + str(i) + ") " + players[i].member.name + "\n" + + # doing phase + + + #send role info to all + send_roles = [p.sendRole() for p in players] + await asyncio.gather(*send_roles) + + + + # query stuff + + #doppelganger stuff + + async def query_seer(): + if seer is None: + return + + await seer.send("Who do you want to look at?") + await seer.sendPoll() + + async def query_robber(): + if robber is None: + return + + await robber.send("Who do you want to rob?") + await robber.sendPoll() + + async def query_troublemaker(): + if troublemaker is None: + return + + await troublemaker.send("Who do you want to exchange?") + await troublemaker.sendPoll() + await troublemaker.sendPoll() + + async def query_drunk(): + if drunk is None: + return + + await drunk.send("Which card from the middle do you want to take?") + await drunk.sendMiddle() + + await asyncio.gather(query_seer(), query_robber(), query_troublemaker(), query_drunk()) + + + + #receive and confirm! + async def receive_seer(): + if seer is not None: + return await seer.receiveChoice() + + async def receive_robber(): + if robber is not None: + return await robber.receiveChoice() + + async def receive_troublemaker(): + if troublemaker is not None: + return await troublemaker.receiveChoice() + + async def receive_drunk(): + if drunk is not None: + return await drunk.receiveChoice() + + seerChoice, robberChoice, troublemakerChoice, drunkChoice = await asyncio.gather(receive_seer(), receive_robber(), receive_troublemaker(), receive_drunk()) + + + + # simulate + + #exchange robber + if robber is not None: + robber.day_role, players[robberChoice].day_role = players[robberChoice].day_role, robber.day_role + #exchange troublemaker + if troublemaker is not None: + A = players[troublemakerChoice[0]] + B = players[troublemakerChoice[1]] + A.day_role, B.day_role = B.day_role, A.day_role + #exchange drunk + if drunk is not None: + drunk.day_role, middle[drunkChoice] = middle[drunkChoice], drunk.day_role + + + + #send werewolves identity to werewolves and minion + async def send_werewolves(): + message = "" + for w in werewolve: + message += w.member.name + " " + + message += "were werewolves" + + sender = [bad.send(message) for bad in werewolve] + if minion is not None: + sender.append(minion.send(message)) + + await asyncio.gather(*sender) + + #send mason identity to masons + async def send_masons(): + message = "" + for m in mason: + message += m.member.name + " " + + message += " were masons" + + sender = [m.send(message) for m in mason] + await asyncio.gather(*sender) + + #send info to seer + async def send_seer(): + if seer is not None: + await seer.send(players[seerChoice].member.name + " was a " + players[seerChoice].night_role.name) + + #send info to robber + async def send_robber(): + if robber is not None: + await robber.send("You stole the role: " + players[robberChoice].night_role.name) + + #send insomniac new role to insomniac + async def send_insomniac(): + if insomniac is not None: + await insomniac.send("You are now a " + insomniac.day_role.name) + + await asyncio.gather(send_werewolves(), send_masons(), send_seer(), send_robber(), send_insomniac()) + + + + # discussion + + # vote + + def check_vote(vote): + return vote.content == "$vote" and vote.channel == message.channel + + await bot.wait_for('message', check = check_vote) + + await message.channel.send("Vote in DM") + + + send_votes = [p.sendPoll() for p in players] + await asyncio.gather(*send_votes) + + receive_votes = [p.receiveChoice() for p in players] + tmp = await asyncio.gather(*receive_votes) + for i in range(Player.size): + players[i].vote = tmp[i] + + for p in players: + players[p.vote].tally += 1 + + maxi = max( [p.tally for p in players] ) + + dead = [p for p in players if p.tally >= maxi] + + if hunter in dead: + dead.append(players[hunter.vote]) + + + + # result and end + # show day-role & night role + + msg = "" + for d in dead: + msg += d.member.name + " " + msg += "are dead!" + await message.channel.send(msg) + + if any(d in werewolve for d in dead): + msg = "The village won!" + else: + msg = "The werewolves won!" + + await message.channel.send(msg) + + msg = "" + for p in players: + msg += p.member.name + ": " + p.day_role.name + " (day) " + p.night_role.name + " (night) and voted for " + players[p.vote].member.name + "\n" + + msg += middle + + await message.channel.send(msg) + + + + running = False + + + +bot.run(TOKEN) \ No newline at end of file diff --git a/src/werewolve-bot.py b/src/werewolve-bot.py new file mode 100644 index 0000000..ccf6601 --- /dev/null +++ b/src/werewolve-bot.py @@ -0,0 +1,499 @@ +import os +import discord +from enum import Enum +from random import shuffle +import asyncio +from dotenv import load_dotenv + +load_dotenv() +TOKEN = os.getenv('DISCORD_TOKEN') +if TOKEN is None: + print("Missing discord token!") + exit(1) + + + +class Role: + + def __init__(self, game): + self.game = game + self.copy = self + + def setPlayer(self, player): + self.player = player + + async def phase1(self): # query stuff + doppelganger simulation + pass + + async def phase2(self): # werewolf stuff + seer info + pass + + 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, game): + for role_class in Role.role_set: + if message.casefold() == role_class.name(): + return role_class(game) + + @classmethod + def name(cls): + return cls.__name__.casefold() + + def __str__(self): + return self.name() + +class Doppelganger(Role): + order = 1 + +class Werewolf(Role): + order = 2 + + 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("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("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") + else: + await self.player.send("Werewolves: " + str(self.game.werewolf_list)) + + +class Mason(Role): + order = 4 + + 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): + order = 5 + + 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(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])) + + +class Robber(Role): + order = 6 + + 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): + Player.swap(self.player, self.player.other()[self.choice]) + await self.player.send("You robbed: " + str(self.player.day_role)) + +class Troublemaker(Role): + order = 7 + + 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): + Player.swap(self.player.other()[self.A], self.player.other()[self.B]) + # receive conformation + await self.player.send("Received " + str(self.A) + " " + str(self.B)) + +class Drunk(Role): + order = 8 + + 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): + order = 9 + + async def phase5(self): + await self.player.send("You are now: " + str(self.player.day_role)) + +class Villiager(Role): + order = 10 + +class Tanner(Role): + order = 11 + +class Hunter(Role): + order = 12 + +class No_role(Role): + order = 1000 + + +Role.role_set = [Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Villiager, Tanner, Hunter] + + +class Player: + + @staticmethod + async def make(member, game): + p = Player() + p.member = member + p.dm = member.dm_channel or await member.create_dm() + p.game = game + return p + + @staticmethod + def swap(player_A, player_B): + player_A.day_role, player_B.day_role = player_B.day_role, player_A.day_role + + def setRole(self, role): + self.night_role = role + self.day_role = role + + def name(self): + return self.member.name + + def __repr__(self): + return self.name() + + def other(self): + return [p for p in self.game.player_list if p != self] + + async def send(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 receive_choice(self, options): + def check(choice): + return choice.channel == self.dm and choice.content.isdigit() and 0 <= int(choice.content) < len(options) + + return int((await self.game.bot.wait_for('message', timeout=30.0, check = check)).content) + + async def get_choice(self, options): + await self.ask_choice(options) + return await self.receive_choice(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() + + +class one_night: + + def __init__(self, bot): + self.running = False + self.bot = bot + self.player_list = [] + self.role_list = Role.role_set + + + def set_channel(self, channel): + self.channel = channel + + + 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 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))) + + # 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.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) #necessary? + + + async def start_night(self): + await asyncio.gather( *[p.send("The night has begun") for p in self.player_list] ) + + async def send_role(self): + 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( *[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, options): + + # vote + 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 + + for p in self.player_list: + p.vote.tally += 1 + + 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 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(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 + tanner_won = False + + # could make it shorter using boolean algebra + if no_dead: + if werewolf_in_game: + werewolf_won = True + else: + village_won = True + else: + if tanner_dead: + tanner_won = True + + if werewolf_dead: + village_won = True + + else: + if werewolf_dead: + village_won = True + else: + if minion_dead: + if werewolf_in_game: + werewolf_won = True + else: + village_won = True + else: + if minion_in_game: + werewolf_won = True + + 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!") + + if village_won: + await self.send("Village won!") + + for d in dead: + if isinstance(d.day_role.copy, Tanner): + await self.send(str(p) + " won a tanner") + + 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.setup() + await self.set_players() + await self.set_roles() + self.distribute_roles() + await self.start_night() + await self.send_role() + + await self.night_phases() + + await self.start_day() + #discussion timer + + options = self.player_list + [No_role(self)] + await self.vote(options) + self.tally(options) + await self.result(*self.who_won(self.who_dead(options))) + + 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") + + + +bot = discord.Client() + +@bot.event +async def on_ready(): + print('We have logged in as {0.user}'.format(bot)) + + + +async def hello(message): + print("Hello") + await message.channel.send('Hello!:regional_indicator_a:') + + print(message.mentions) + +@bot.event +async def on_message(message): + + global running + + if message.author == bot.user: + return + + + if message.content.startswith('$hello'): + await hello(message) + return + + + if message.content.startswith('$logout'): + await bot.logout() + return + + + if message.content.startswith('$werewolf'): + + # start (only one instance running) + + if werewolf_game.running: + await message.channel.send("Sorry! A game is already running") + return + + werewolf_game.running = True + werewolf_game.set_channel(message.channel) + + + await werewolf_game.game() + + return + +werewolf_game = one_night(bot) +bot.run(TOKEN)