werewolve-bot/werewolve-bot.py

371 lines
7.7 KiB
Python
Raw Normal View History

2020-03-23 18:58:13 +01:00
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)