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 = 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=10.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 @bot.event async def on_message(message): global running if message.author == bot.user: return if message.content.startswith('$hello'): 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) 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.mason, Role.mason, Role.seer, Role.robber, Role.troublemaker] + (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_cards = 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" await message.channel.send(msg) running = False bot.run(TOKEN)