381 lines
7.9 KiB
Python
381 lines
7.9 KiB
Python
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) |