organize in several files

This commit is contained in:
Bibin Muttappillil 2020-04-02 20:47:11 +02:00
parent 15b695851d
commit 9b367001b4
10 changed files with 495 additions and 879 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

65
src/werewolf_bot.py Normal file
View File

@ -0,0 +1,65 @@
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)

218
src/werewolf_game.py Normal file
View File

@ -0,0 +1,218 @@
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")

56
src/werewolf_players.py Normal file
View File

@ -0,0 +1,56 @@
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()

156
src/werewolf_roles.py Normal file
View File

@ -0,0 +1,156 @@
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]

View File

@ -1,381 +0,0 @@
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)

View File

@ -1,498 +0,0 @@
import os
import discord
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(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_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)