|
|
@ -13,18 +13,18 @@ class Game:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
default_secret_channel = {
|
|
|
|
default_secret_channel = {
|
|
|
|
"channel": None,
|
|
|
|
"channel": None,
|
|
|
|
"players": [],
|
|
|
|
"players": [],
|
|
|
|
"votegroup": None # uninitialized VoteGroup
|
|
|
|
"votegroup": None # uninitialized VoteGroup
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
morning_messages = [
|
|
|
|
morning_messages = [
|
|
|
|
"**The sun rises on day {} in the village..**",
|
|
|
|
"**The sun rises on day {} in the village..**",
|
|
|
|
"**Morning has arrived on day {}..**"
|
|
|
|
"**Morning has arrived on day {}..**"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
day_vote_count = 3
|
|
|
|
day_vote_count = 3
|
|
|
|
|
|
|
|
|
|
|
|
# def __new__(cls, guild, game_code):
|
|
|
|
# def __new__(cls, guild, game_code):
|
|
|
|
# game_code = ["VanillaWerewolf", "Villager", "Villager"]
|
|
|
|
# game_code = ["VanillaWerewolf", "Villager", "Villager"]
|
|
|
|
#
|
|
|
|
#
|
|
|
@ -33,28 +33,28 @@ class Game:
|
|
|
|
def __init__(self, guild, game_code):
|
|
|
|
def __init__(self, guild, game_code):
|
|
|
|
self.guild = guild
|
|
|
|
self.guild = guild
|
|
|
|
self.game_code = ["VanillaWerewolf"]
|
|
|
|
self.game_code = ["VanillaWerewolf"]
|
|
|
|
|
|
|
|
|
|
|
|
self.roles = []
|
|
|
|
self.roles = []
|
|
|
|
|
|
|
|
|
|
|
|
self.players = []
|
|
|
|
self.players = []
|
|
|
|
|
|
|
|
|
|
|
|
self.day_vote = {} # author: target
|
|
|
|
self.day_vote = {} # author: target
|
|
|
|
self.vote_totals = {} # id: total_votes
|
|
|
|
self.vote_totals = {} # id: total_votes
|
|
|
|
|
|
|
|
|
|
|
|
self.started = False
|
|
|
|
self.started = False
|
|
|
|
self.game_over = False
|
|
|
|
self.game_over = False
|
|
|
|
self.can_vote = False
|
|
|
|
self.can_vote = False
|
|
|
|
self.used_votes = 0
|
|
|
|
self.used_votes = 0
|
|
|
|
|
|
|
|
|
|
|
|
self.day_time = False
|
|
|
|
self.day_time = False
|
|
|
|
self.day_count = 0
|
|
|
|
self.day_count = 0
|
|
|
|
|
|
|
|
|
|
|
|
self.channel_category = None
|
|
|
|
self.channel_category = None
|
|
|
|
self.village_channel = None
|
|
|
|
self.village_channel = None
|
|
|
|
|
|
|
|
|
|
|
|
self.p_channels = {} # uses default_secret_channel
|
|
|
|
self.p_channels = {} # uses default_secret_channel
|
|
|
|
self.vote_groups = {} # ID : VoteGroup()
|
|
|
|
self.vote_groups = {} # ID : VoteGroup()
|
|
|
|
|
|
|
|
|
|
|
|
self.night_results = []
|
|
|
|
self.night_results = []
|
|
|
|
|
|
|
|
|
|
|
|
self.loop = asyncio.get_event_loop()
|
|
|
|
self.loop = asyncio.get_event_loop()
|
|
|
@ -76,58 +76,58 @@ class Game:
|
|
|
|
await ctx.send("Player count does not match role count, cannot start")
|
|
|
|
await ctx.send("Player count does not match role count, cannot start")
|
|
|
|
self.roles = []
|
|
|
|
self.roles = []
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
await self.assign_roles()
|
|
|
|
await self.assign_roles()
|
|
|
|
|
|
|
|
|
|
|
|
# Create category and channel with individual overwrites
|
|
|
|
# Create category and channel with individual overwrites
|
|
|
|
overwrite = {
|
|
|
|
overwrite = {
|
|
|
|
self.guild.default_role: discord.PermissionOverwrite(read_messages=False, send_messages=True),
|
|
|
|
self.guild.default_role: discord.PermissionOverwrite(read_messages=False, send_messages=True),
|
|
|
|
self.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
|
|
|
self.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.channel_category = await self.guild.create_category("ww-game", overwrites=overwrite, reason="New game of "
|
|
|
|
self.channel_category = await self.guild.create_category("ww-game", overwrites=overwrite, reason="New game of "
|
|
|
|
"werewolf")
|
|
|
|
"werewolf")
|
|
|
|
|
|
|
|
|
|
|
|
for player in self.players:
|
|
|
|
for player in self.players:
|
|
|
|
overwrite[player.member] = discord.PermissionOverwrite(read_messages=True)
|
|
|
|
overwrite[player.member] = discord.PermissionOverwrite(read_messages=True)
|
|
|
|
|
|
|
|
|
|
|
|
self.village_channel = await self.guild.create_text_channel("Village Square",
|
|
|
|
self.village_channel = await self.guild.create_text_channel("Village Square",
|
|
|
|
overwrites=overwrite,
|
|
|
|
overwrites=overwrite,
|
|
|
|
reason="New game of werewolf",
|
|
|
|
reason="New game of werewolf",
|
|
|
|
category=self.channel_category)
|
|
|
|
category=self.channel_category)
|
|
|
|
|
|
|
|
|
|
|
|
# Assuming everything worked so far
|
|
|
|
# Assuming everything worked so far
|
|
|
|
print("Pre at_game_start")
|
|
|
|
print("Pre at_game_start")
|
|
|
|
await self._at_game_start() # This will queue channels and votegroups to be made
|
|
|
|
await self._at_game_start() # This will queue channels and votegroups to be made
|
|
|
|
print("Post at_game_start")
|
|
|
|
print("Post at_game_start")
|
|
|
|
for channel_id in self.p_channels:
|
|
|
|
for channel_id in self.p_channels:
|
|
|
|
print("Channel id: "+channel_id)
|
|
|
|
print("Channel id: " + channel_id)
|
|
|
|
overwrite = {
|
|
|
|
overwrite = {
|
|
|
|
self.guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
|
|
|
self.guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
|
|
|
self.guild.me: discord.PermissionOverwrite(read_messages=True)
|
|
|
|
self.guild.me: discord.PermissionOverwrite(read_messages=True)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for player in self.p_channels[channel_id]["players"]:
|
|
|
|
for player in self.p_channels[channel_id]["players"]:
|
|
|
|
overwrite[player.member] = discord.PermissionOverwrite(read_messages=True)
|
|
|
|
overwrite[player.member] = discord.PermissionOverwrite(read_messages=True)
|
|
|
|
|
|
|
|
|
|
|
|
channel = await self.guild.create_text_channel(channel_id,
|
|
|
|
channel = await self.guild.create_text_channel(channel_id,
|
|
|
|
overwrites=overwrite,
|
|
|
|
overwrites=overwrite,
|
|
|
|
reason="Ww game secret channel",
|
|
|
|
reason="Ww game secret channel",
|
|
|
|
category=self.channel_category)
|
|
|
|
category=self.channel_category)
|
|
|
|
|
|
|
|
|
|
|
|
self.p_channels[channel_id]["channel"] = channel
|
|
|
|
self.p_channels[channel_id]["channel"] = channel
|
|
|
|
|
|
|
|
|
|
|
|
if self.p_channels[channel_id]["votegroup"] is not None:
|
|
|
|
if self.p_channels[channel_id]["votegroup"] is not None:
|
|
|
|
vote_group = self.p_channels[channel_id]["votegroup"](self, channel)
|
|
|
|
vote_group = self.p_channels[channel_id]["votegroup"](self, channel)
|
|
|
|
|
|
|
|
|
|
|
|
await vote_group.register_players(*self.p_channels[channel_id]["players"])
|
|
|
|
await vote_group.register_players(*self.p_channels[channel_id]["players"])
|
|
|
|
|
|
|
|
|
|
|
|
self.vote_groups[channel_id] = vote_group
|
|
|
|
self.vote_groups[channel_id] = vote_group
|
|
|
|
|
|
|
|
|
|
|
|
print("Pre-cycle")
|
|
|
|
print("Pre-cycle")
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
asyncio.ensure_future(self._cycle()) # Start the loop
|
|
|
|
asyncio.ensure_future(self._cycle()) # Start the loop
|
|
|
|
|
|
|
|
|
|
|
|
############START Notify structure############
|
|
|
|
############START Notify structure############
|
|
|
|
async def _cycle(self):
|
|
|
|
async def _cycle(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -147,14 +147,14 @@ class Game:
|
|
|
|
await self._at_day_start()
|
|
|
|
await self._at_day_start()
|
|
|
|
# Once cycle ends, this will trigger end_game
|
|
|
|
# Once cycle ends, this will trigger end_game
|
|
|
|
await self._end_game() # Handle open channels
|
|
|
|
await self._end_game() # Handle open channels
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_game_start(self): # ID 0
|
|
|
|
async def _at_game_start(self): # ID 0
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
await self.village_channel.send(
|
|
|
|
await self.village_channel.send(
|
|
|
|
embed=discord.Embed(title="Game is starting, please wait for setup to complete"))
|
|
|
|
embed=discord.Embed(title="Game is starting, please wait for setup to complete"))
|
|
|
|
|
|
|
|
|
|
|
|
await self._notify(0)
|
|
|
|
await self._notify(0)
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_day_start(self): # ID 1
|
|
|
|
async def _at_day_start(self): # ID 1
|
|
|
@ -164,82 +164,82 @@ class Game:
|
|
|
|
def check():
|
|
|
|
def check():
|
|
|
|
return not self.can_vote or not self.day_time or self.game_over
|
|
|
|
return not self.can_vote or not self.day_time or self.game_over
|
|
|
|
|
|
|
|
|
|
|
|
self.day_count += 1
|
|
|
|
self.day_count += 1
|
|
|
|
embed=discord.Embed(title=random.choice(self.morning_messages).format(self.day_count))
|
|
|
|
embed = discord.Embed(title=random.choice(self.morning_messages).format(self.day_count))
|
|
|
|
for result in self.night_results:
|
|
|
|
for result in self.night_results:
|
|
|
|
embed.add_field(name=result, value="________", inline=False)
|
|
|
|
embed.add_field(name=result, value="________", inline=False)
|
|
|
|
|
|
|
|
|
|
|
|
self.day_time = True
|
|
|
|
self.day_time = True
|
|
|
|
|
|
|
|
|
|
|
|
self.night_results = [] # Clear for next day
|
|
|
|
self.night_results = [] # Clear for next day
|
|
|
|
|
|
|
|
|
|
|
|
await self.village_channel.send(embed=embed)
|
|
|
|
await self.village_channel.send(embed=embed)
|
|
|
|
await self.generate_targets(self.village_channel)
|
|
|
|
await self.generate_targets(self.village_channel)
|
|
|
|
|
|
|
|
|
|
|
|
await self.day_perms(self.village_channel)
|
|
|
|
await self.day_perms(self.village_channel)
|
|
|
|
await self._notify(1)
|
|
|
|
await self._notify(1)
|
|
|
|
|
|
|
|
|
|
|
|
await self._check_game_over()
|
|
|
|
await self._check_game_over()
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
self.can_vote = True
|
|
|
|
self.can_vote = True
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(120) # 4 minute days
|
|
|
|
await asyncio.sleep(120) # 4 minute days
|
|
|
|
if check():
|
|
|
|
if check():
|
|
|
|
return
|
|
|
|
return
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Two minutes of daylight remain...**"))
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Two minutes of daylight remain...**"))
|
|
|
|
await asyncio.sleep(120) # 4 minute days
|
|
|
|
await asyncio.sleep(120) # 4 minute days
|
|
|
|
|
|
|
|
|
|
|
|
# Need a loop here to wait for trial to end (can_vote?)
|
|
|
|
# Need a loop here to wait for trial to end (can_vote?)
|
|
|
|
|
|
|
|
|
|
|
|
if check():
|
|
|
|
if check():
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
await self._at_day_end()
|
|
|
|
await self._at_day_end()
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_voted(self, target): # ID 2
|
|
|
|
async def _at_voted(self, target): # ID 2
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
data = {"player": target}
|
|
|
|
data = {"player": target}
|
|
|
|
await self._notify(2, data)
|
|
|
|
await self._notify(2, data)
|
|
|
|
|
|
|
|
|
|
|
|
self.used_votes += 1
|
|
|
|
self.used_votes += 1
|
|
|
|
|
|
|
|
|
|
|
|
self.can_vote = False
|
|
|
|
self.can_vote = False
|
|
|
|
await self.speech_perms(self.village_channel, target.member)
|
|
|
|
await self.speech_perms(self.village_channel, target.member)
|
|
|
|
await self.village_channel.send(
|
|
|
|
await self.village_channel.send(
|
|
|
|
"**{} will be put to trial and has 30 seconds to defend themselves**".format(target.mention))
|
|
|
|
"**{} will be put to trial and has 30 seconds to defend themselves**".format(target.mention))
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(30)
|
|
|
|
await asyncio.sleep(30)
|
|
|
|
|
|
|
|
|
|
|
|
await self.speech_perms(self.village_channel, target.member, undo=True)
|
|
|
|
await self.speech_perms(self.village_channel, target.member, undo=True)
|
|
|
|
|
|
|
|
|
|
|
|
message = await self.village_channel.send(
|
|
|
|
message = await self.village_channel.send(
|
|
|
|
"Everyone will now vote whether to lynch {}\n"
|
|
|
|
"Everyone will now vote whether to lynch {}\n"
|
|
|
|
"👍 to save, 👎 to lynch\n"
|
|
|
|
"👍 to save, 👎 to lynch\n"
|
|
|
|
"*Majority rules, no-lynch on ties, "
|
|
|
|
"*Majority rules, no-lynch on ties, "
|
|
|
|
"vote both or neither to abstain, 15 seconds to vote*".format(target.mention))
|
|
|
|
"vote both or neither to abstain, 15 seconds to vote*".format(target.mention))
|
|
|
|
|
|
|
|
|
|
|
|
await self.village_channel.add_reaction("👍")
|
|
|
|
await self.village_channel.add_reaction("👍")
|
|
|
|
await self.village_channel.add_reaction("👎")
|
|
|
|
await self.village_channel.add_reaction("👎")
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(15)
|
|
|
|
await asyncio.sleep(15)
|
|
|
|
|
|
|
|
|
|
|
|
reaction_list = message.reactions
|
|
|
|
reaction_list = message.reactions
|
|
|
|
|
|
|
|
|
|
|
|
up_votes = sum(p.emoji == "👍" and not p.me for p in reaction_list)
|
|
|
|
up_votes = sum(p.emoji == "👍" and not p.me for p in reaction_list)
|
|
|
|
down_votes = sum(p.emoji == "👎" and not p.me for p in reaction_list)
|
|
|
|
down_votes = sum(p.emoji == "👎" and not p.me for p in reaction_list)
|
|
|
|
|
|
|
|
|
|
|
|
if len(down_votes) > len(up_votes):
|
|
|
|
if len(down_votes) > len(up_votes):
|
|
|
|
embed=discord.Embed(title="Vote Results", color=0xff0000)
|
|
|
|
embed = discord.Embed(title="Vote Results", color=0xff0000)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
embed=discord.Embed(title="Vote Results", color=0x80ff80)
|
|
|
|
embed = discord.Embed(title="Vote Results", color=0x80ff80)
|
|
|
|
|
|
|
|
|
|
|
|
embed.add_field(name="👎", value="**{}**".format(len(up_votes)), inline=True)
|
|
|
|
embed.add_field(name="👎", value="**{}**".format(len(up_votes)), inline=True)
|
|
|
|
embed.add_field(name="👍", value="**{}**".format(len(down_votes)), inline=True)
|
|
|
|
embed.add_field(name="👍", value="**{}**".format(len(down_votes)), inline=True)
|
|
|
|
|
|
|
|
|
|
|
|
await self.village_channel.send(embed=embed)
|
|
|
|
await self.village_channel.send(embed=embed)
|
|
|
|
|
|
|
|
|
|
|
|
if len(down_votes) > len(up_votes):
|
|
|
|
if len(down_votes) > len(up_votes):
|
|
|
|
await self.village_channel.send("**Voted to lynch {}!**".format(target.mention))
|
|
|
|
await self.village_channel.send("**Voted to lynch {}!**".format(target.mention))
|
|
|
|
await self.lynch(target)
|
|
|
|
await self.lynch(target)
|
|
|
@ -256,19 +256,19 @@ class Game:
|
|
|
|
|
|
|
|
|
|
|
|
if not self.can_vote:
|
|
|
|
if not self.can_vote:
|
|
|
|
await self._at_day_end()
|
|
|
|
await self._at_day_end()
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_kill(self, target): # ID 3
|
|
|
|
async def _at_kill(self, target): # ID 3
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
data = {"player": target}
|
|
|
|
data = {"player": target}
|
|
|
|
await self._notify(3, data)
|
|
|
|
await self._notify(3, data)
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_hang(self, target): # ID 4
|
|
|
|
async def _at_hang(self, target): # ID 4
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
data = {"player": target}
|
|
|
|
data = {"player": target}
|
|
|
|
await self._notify(4, data)
|
|
|
|
await self._notify(4, data)
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_day_end(self): # ID 5
|
|
|
|
async def _at_day_end(self): # ID 5
|
|
|
|
await self._check_game_over()
|
|
|
|
await self._check_game_over()
|
|
|
|
|
|
|
|
|
|
|
@ -279,36 +279,36 @@ class Game:
|
|
|
|
self.day_vote = {}
|
|
|
|
self.day_vote = {}
|
|
|
|
self.vote_totals = {}
|
|
|
|
self.vote_totals = {}
|
|
|
|
self.day_time = False
|
|
|
|
self.day_time = False
|
|
|
|
|
|
|
|
|
|
|
|
await self.night_perms(self.village_channel)
|
|
|
|
await self.night_perms(self.village_channel)
|
|
|
|
|
|
|
|
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**The sun sets on the village...**"))
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**The sun sets on the village...**"))
|
|
|
|
|
|
|
|
|
|
|
|
await self._notify(5)
|
|
|
|
await self._notify(5)
|
|
|
|
await asyncio.sleep(5)
|
|
|
|
await asyncio.sleep(5)
|
|
|
|
await self._at_night_start()
|
|
|
|
await self._at_night_start()
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_night_start(self): # ID 6
|
|
|
|
async def _at_night_start(self): # ID 6
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
await self._notify(6)
|
|
|
|
await self._notify(6)
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(120) # 2 minutes
|
|
|
|
await asyncio.sleep(120) # 2 minutes
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Two minutes of night remain...**"))
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Two minutes of night remain...**"))
|
|
|
|
await asyncio.sleep(90) # 1.5 minutes
|
|
|
|
await asyncio.sleep(90) # 1.5 minutes
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Thirty seconds until sunrise...**"))
|
|
|
|
await self.village_channel.send(embed=discord.Embed(title="**Thirty seconds until sunrise...**"))
|
|
|
|
await asyncio.sleep(30) # .5 minutes
|
|
|
|
await asyncio.sleep(30) # .5 minutes
|
|
|
|
|
|
|
|
|
|
|
|
await self._at_night_end()
|
|
|
|
await self._at_night_end()
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_night_end(self): # ID 7
|
|
|
|
async def _at_night_end(self): # ID 7
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
await self._notify(7)
|
|
|
|
await self._notify(7)
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(15)
|
|
|
|
await asyncio.sleep(15)
|
|
|
|
await self._at_day_start()
|
|
|
|
await self._at_day_start()
|
|
|
|
|
|
|
|
|
|
|
|
async def _at_visit(self, target, source): # ID 8
|
|
|
|
async def _at_visit(self, target, source): # ID 8
|
|
|
|
if self.game_over:
|
|
|
|
if self.game_over:
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -316,24 +316,24 @@ class Game:
|
|
|
|
await self._notify(8, data)
|
|
|
|
await self._notify(8, data)
|
|
|
|
|
|
|
|
|
|
|
|
async def _notify(self, event, data=None):
|
|
|
|
async def _notify(self, event, data=None):
|
|
|
|
for i in range(1,7): # action guide 1-6 (0 is no action)
|
|
|
|
for i in range(1, 7): # action guide 1-6 (0 is no action)
|
|
|
|
tasks = []
|
|
|
|
tasks = []
|
|
|
|
# Role priorities
|
|
|
|
# Role priorities
|
|
|
|
role_order = [role for role in self.roles if role.action_list[event][1]==i]
|
|
|
|
role_order = [role for role in self.roles if role.action_list[event][1] == i]
|
|
|
|
for role in role_order:
|
|
|
|
for role in role_order:
|
|
|
|
tasks.append(asyncio.ensure_future(role.on_event(event, data), loop=self.loop))
|
|
|
|
tasks.append(asyncio.ensure_future(role.on_event(event, data), loop=self.loop))
|
|
|
|
# VoteGroup priorities
|
|
|
|
# VoteGroup priorities
|
|
|
|
vote_order = [vg for vg in self.vote_groups.values() if vg.action_list[event][1]==i]
|
|
|
|
vote_order = [vg for vg in self.vote_groups.values() if vg.action_list[event][1] == i]
|
|
|
|
for vote_group in vote_order:
|
|
|
|
for vote_group in vote_order:
|
|
|
|
tasks.append(asyncio.ensure_future(vote_group.on_event(event, data), loop=self.loop))
|
|
|
|
tasks.append(asyncio.ensure_future(vote_group.on_event(event, data), loop=self.loop))
|
|
|
|
if tasks:
|
|
|
|
if tasks:
|
|
|
|
await asyncio.gather(*tasks)
|
|
|
|
await asyncio.gather(*tasks)
|
|
|
|
# Run same-priority task simultaneously
|
|
|
|
# Run same-priority task simultaneously
|
|
|
|
|
|
|
|
|
|
|
|
############END Notify structure############
|
|
|
|
############END Notify structure############
|
|
|
|
|
|
|
|
|
|
|
|
async def generate_targets(self, channel):
|
|
|
|
async def generate_targets(self, channel):
|
|
|
|
embed=discord.Embed(title="Remaining Players")
|
|
|
|
embed = discord.Embed(title="Remaining Players")
|
|
|
|
for i in range(len(self.players)):
|
|
|
|
for i in range(len(self.players)):
|
|
|
|
player = self.players[i]
|
|
|
|
player = self.players[i]
|
|
|
|
if player.alive:
|
|
|
|
if player.alive:
|
|
|
@ -342,7 +342,7 @@ class Game:
|
|
|
|
status = "*Dead*"
|
|
|
|
status = "*Dead*"
|
|
|
|
embed.add_field(name="ID# **{}**".format(i),
|
|
|
|
embed.add_field(name="ID# **{}**".format(i),
|
|
|
|
value="{} {}".format(status, player.member.display_name), inline=True)
|
|
|
|
value="{} {}".format(status, player.member.display_name), inline=True)
|
|
|
|
|
|
|
|
|
|
|
|
return await channel.send(embed=embed)
|
|
|
|
return await channel.send(embed=embed)
|
|
|
|
|
|
|
|
|
|
|
|
async def register_channel(self, channel_id, role, votegroup=None):
|
|
|
|
async def register_channel(self, channel_id, role, votegroup=None):
|
|
|
@ -353,9 +353,9 @@ class Game:
|
|
|
|
self.p_channels[channel_id] = self.default_secret_channel.copy()
|
|
|
|
self.p_channels[channel_id] = self.default_secret_channel.copy()
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(1) # This will have multiple calls
|
|
|
|
await asyncio.sleep(1) # This will have multiple calls
|
|
|
|
|
|
|
|
|
|
|
|
self.p_channels[channel_id]["players"].append(role.player)
|
|
|
|
self.p_channels[channel_id]["players"].append(role.player)
|
|
|
|
|
|
|
|
|
|
|
|
if votegroup:
|
|
|
|
if votegroup:
|
|
|
|
self.p_channels[channel_id]["votegroup"] = votegroup
|
|
|
|
self.p_channels[channel_id]["votegroup"] = votegroup
|
|
|
|
|
|
|
|
|
|
|
@ -365,23 +365,23 @@ class Game:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if self.started:
|
|
|
|
if self.started:
|
|
|
|
await channel.send("**Game has already started!**")
|
|
|
|
await channel.send("**Game has already started!**")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if await self.get_player_by_member(member) is not None:
|
|
|
|
if await self.get_player_by_member(member) is not None:
|
|
|
|
await channel.send("{} is already in the game!".format(member.mention))
|
|
|
|
await channel.send("{} is already in the game!".format(member.mention))
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
self.players.append(Player(member))
|
|
|
|
self.players.append(Player(member))
|
|
|
|
|
|
|
|
|
|
|
|
await channel.send("{} has been added to the game, "
|
|
|
|
await channel.send("{} has been added to the game, "
|
|
|
|
"total players is **{}**".format(member.mention, len(self.players)))
|
|
|
|
"total players is **{}**".format(member.mention, len(self.players)))
|
|
|
|
|
|
|
|
|
|
|
|
async def quit(self, member: discord.Member, channel: discord.TextChannel = None):
|
|
|
|
async def quit(self, member: discord.Member, channel: discord.TextChannel = None):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Have a member quit a game
|
|
|
|
Have a member quit a game
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
player = await self.get_player_by_member(member)
|
|
|
|
player = await self.get_player_by_member(member)
|
|
|
|
|
|
|
|
|
|
|
|
if player is None:
|
|
|
|
if player is None:
|
|
|
|
return "You're not in a game!"
|
|
|
|
return "You're not in a game!"
|
|
|
|
|
|
|
|
|
|
|
@ -391,22 +391,22 @@ class Game:
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.players = [player for player in self.players if player.member != member]
|
|
|
|
self.players = [player for player in self.players if player.member != member]
|
|
|
|
await channel.send("{} chickened out, player count is now **{}**".format(member.mention, len(self.players)))
|
|
|
|
await channel.send("{} chickened out, player count is now **{}**".format(member.mention, len(self.players)))
|
|
|
|
|
|
|
|
|
|
|
|
async def choose(self, ctx, data):
|
|
|
|
async def choose(self, ctx, data):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Arbitrary decision making
|
|
|
|
Arbitrary decision making
|
|
|
|
Example: seer picking target to see
|
|
|
|
Example: seer picking target to see
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
player = await self.get_player_by_member(ctx.author)
|
|
|
|
player = await self.get_player_by_member(ctx.author)
|
|
|
|
|
|
|
|
|
|
|
|
if player is None:
|
|
|
|
if player is None:
|
|
|
|
await ctx.send("You're not in this game!")
|
|
|
|
await ctx.send("You're not in this game!")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if not player.alive:
|
|
|
|
if not player.alive:
|
|
|
|
await ctx.send("**Corpses** can't vote...")
|
|
|
|
await ctx.send("**Corpses** can't vote...")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if player.role.blocked:
|
|
|
|
if player.role.blocked:
|
|
|
|
await ctx.send("Something is preventing you from doing this...")
|
|
|
|
await ctx.send("Something is preventing you from doing this...")
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -419,7 +419,7 @@ class Game:
|
|
|
|
async def _visit(self, target, source):
|
|
|
|
async def _visit(self, target, source):
|
|
|
|
await target.role.visit(source)
|
|
|
|
await target.role.visit(source)
|
|
|
|
await self._at_visit(target, source)
|
|
|
|
await self._at_visit(target, source)
|
|
|
|
|
|
|
|
|
|
|
|
async def visit(self, target_id, source):
|
|
|
|
async def visit(self, target_id, source):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Night visit target_id
|
|
|
|
Night visit target_id
|
|
|
@ -438,15 +438,15 @@ class Game:
|
|
|
|
Also used in vote groups
|
|
|
|
Also used in vote groups
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
player = await self.get_player_by_member(author)
|
|
|
|
player = await self.get_player_by_member(author)
|
|
|
|
|
|
|
|
|
|
|
|
if player is None:
|
|
|
|
if player is None:
|
|
|
|
await channel.send("You're not in this game!")
|
|
|
|
await channel.send("You're not in this game!")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if not player.alive:
|
|
|
|
if not player.alive:
|
|
|
|
await channel.send("Corpses can't vote")
|
|
|
|
await channel.send("Corpses can't vote")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if channel == self.village_channel:
|
|
|
|
if channel == self.village_channel:
|
|
|
|
if not self.can_vote:
|
|
|
|
if not self.can_vote:
|
|
|
|
await channel.send("Voting is not allowed right now")
|
|
|
|
await channel.send("Voting is not allowed right now")
|
|
|
@ -462,11 +462,11 @@ class Game:
|
|
|
|
target = self.players[target_id]
|
|
|
|
target = self.players[target_id]
|
|
|
|
except IndexError:
|
|
|
|
except IndexError:
|
|
|
|
target = None
|
|
|
|
target = None
|
|
|
|
|
|
|
|
|
|
|
|
if target is None:
|
|
|
|
if target is None:
|
|
|
|
await channel.send("Not a valid ID")
|
|
|
|
await channel.send("Not a valid ID")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# Now handle village vote or send to votegroup
|
|
|
|
# Now handle village vote or send to votegroup
|
|
|
|
if channel == self.village_channel:
|
|
|
|
if channel == self.village_channel:
|
|
|
|
await self._village_vote(target, author, target_id)
|
|
|
|
await self._village_vote(target, author, target_id)
|
|
|
@ -475,19 +475,19 @@ class Game:
|
|
|
|
else: # Somehow previous check failed
|
|
|
|
else: # Somehow previous check failed
|
|
|
|
await channel.send("Cannot vote in this channel")
|
|
|
|
await channel.send("Cannot vote in this channel")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
async def _village_vote(self, target, author, target_id):
|
|
|
|
async def _village_vote(self, target, author, target_id):
|
|
|
|
if author in self.day_vote:
|
|
|
|
if author in self.day_vote:
|
|
|
|
self.vote_totals[self.day_vote[author]] -= 1
|
|
|
|
self.vote_totals[self.day_vote[author]] -= 1
|
|
|
|
|
|
|
|
|
|
|
|
self.day_vote[author] = target_id
|
|
|
|
self.day_vote[author] = target_id
|
|
|
|
if target_id not in self.vote_totals:
|
|
|
|
if target_id not in self.vote_totals:
|
|
|
|
self.vote_totals[target_id] = 1
|
|
|
|
self.vote_totals[target_id] = 1
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.vote_totals[target_id] += 1
|
|
|
|
self.vote_totals[target_id] += 1
|
|
|
|
|
|
|
|
|
|
|
|
required_votes = len([player for player in self.players if player.alive]) // 7 + 2
|
|
|
|
required_votes = len([player for player in self.players if player.alive]) // 7 + 2
|
|
|
|
|
|
|
|
|
|
|
|
if self.vote_totals[target_id] < required_votes:
|
|
|
|
if self.vote_totals[target_id] < required_votes:
|
|
|
|
await self.village_channel.send(""
|
|
|
|
await self.village_channel.send(""
|
|
|
|
"{} has voted to put {} to trial. "
|
|
|
|
"{} has voted to put {} to trial. "
|
|
|
@ -503,7 +503,7 @@ class Game:
|
|
|
|
if method is not None:
|
|
|
|
if method is not None:
|
|
|
|
out = "**{ID}** - " + method
|
|
|
|
out = "**{ID}** - " + method
|
|
|
|
return out.format(ID=target.id, target=target.member.display_name)
|
|
|
|
return out.format(ID=target.id, target=target.member.display_name)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return "**{ID}** - {target} was found dead".format(ID=target.id, target=target.member.display_name)
|
|
|
|
return "**{ID}** - {target} was found dead".format(ID=target.id, target=target.member.display_name)
|
|
|
|
|
|
|
|
|
|
|
|
async def _quit(self, player):
|
|
|
|
async def _quit(self, player):
|
|
|
@ -517,29 +517,29 @@ class Game:
|
|
|
|
await self.dead_perms(self.village_channel, player.member)
|
|
|
|
await self.dead_perms(self.village_channel, player.member)
|
|
|
|
# Add a punishment system for quitting games later
|
|
|
|
# Add a punishment system for quitting games later
|
|
|
|
|
|
|
|
|
|
|
|
async def kill(self, target_id, source=None, method: str=None, novisit=False):
|
|
|
|
async def kill(self, target_id, source=None, method: str = None, novisit=False):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Attempt to kill a target
|
|
|
|
Attempt to kill a target
|
|
|
|
Source allows admin override
|
|
|
|
Source allows admin override
|
|
|
|
Be sure to remove permissions appropriately
|
|
|
|
Be sure to remove permissions appropriately
|
|
|
|
Important to finish execution before triggering notify
|
|
|
|
Important to finish execution before triggering notify
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
if source is None:
|
|
|
|
if source is None:
|
|
|
|
target = self.players[target_id]
|
|
|
|
target = self.players[target_id]
|
|
|
|
elif self.day_time:
|
|
|
|
elif self.day_time:
|
|
|
|
target = self.get_day_target(target_id, source)
|
|
|
|
target = self.get_day_target(target_id, source)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
target = await self.get_night_target(target_id, source)
|
|
|
|
target = await self.get_night_target(target_id, source)
|
|
|
|
if source is not None:
|
|
|
|
if source is not None:
|
|
|
|
if source.role.blocked:
|
|
|
|
if source.role.blocked:
|
|
|
|
# Do nothing if blocked, blocker handles text
|
|
|
|
# Do nothing if blocked, blocker handles text
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if not novisit:
|
|
|
|
if not novisit:
|
|
|
|
# Arsonist wouldn't visit before killing
|
|
|
|
# Arsonist wouldn't visit before killing
|
|
|
|
await self._visit(target, source) # Visit before killing
|
|
|
|
await self._visit(target, source) # Visit before killing
|
|
|
|
|
|
|
|
|
|
|
|
if not target.protected:
|
|
|
|
if not target.protected:
|
|
|
|
target.alive = False
|
|
|
|
target.alive = False
|
|
|
|
await target.kill(source)
|
|
|
|
await target.kill(source)
|
|
|
@ -550,8 +550,8 @@ class Game:
|
|
|
|
await self.dead_perms(self.village_channel, target.member)
|
|
|
|
await self.dead_perms(self.village_channel, target.member)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
target.protected = False
|
|
|
|
target.protected = False
|
|
|
|
|
|
|
|
|
|
|
|
async def lynch(self, target_id):
|
|
|
|
async def lynch(self, target_id):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Attempt to lynch a target
|
|
|
|
Attempt to lynch a target
|
|
|
|
Important to finish execution before triggering notify
|
|
|
|
Important to finish execution before triggering notify
|
|
|
@ -561,67 +561,67 @@ class Game:
|
|
|
|
await self._at_hang(target)
|
|
|
|
await self._at_hang(target)
|
|
|
|
if not target.alive: # Still dead after notifying
|
|
|
|
if not target.alive: # Still dead after notifying
|
|
|
|
await self.dead_perms(self.village_channel, target.member)
|
|
|
|
await self.dead_perms(self.village_channel, target.member)
|
|
|
|
|
|
|
|
|
|
|
|
async def get_night_target(self, target_id, source=None):
|
|
|
|
async def get_night_target(self, target_id, source=None):
|
|
|
|
return self.players[target_id] # For now
|
|
|
|
return self.players[target_id] # For now
|
|
|
|
|
|
|
|
|
|
|
|
async def get_day_target(self, target_id, source=None):
|
|
|
|
async def get_day_target(self, target_id, source=None):
|
|
|
|
return self.players[target_id] # For now
|
|
|
|
return self.players[target_id] # For now
|
|
|
|
|
|
|
|
|
|
|
|
async def get_roles(self, game_code=None):
|
|
|
|
async def get_roles(self, game_code=None):
|
|
|
|
if game_code is not None:
|
|
|
|
if game_code is not None:
|
|
|
|
self.game_code = game_code
|
|
|
|
self.game_code = game_code
|
|
|
|
|
|
|
|
|
|
|
|
if self.game_code is None:
|
|
|
|
if self.game_code is None:
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
self.roles = await parse_code(self.game_code)
|
|
|
|
self.roles = await parse_code(self.game_code)
|
|
|
|
|
|
|
|
|
|
|
|
if not self.roles:
|
|
|
|
if not self.roles:
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
async def assign_roles(self):
|
|
|
|
async def assign_roles(self):
|
|
|
|
"""len(self.roles) must == len(self.players)"""
|
|
|
|
"""len(self.roles) must == len(self.players)"""
|
|
|
|
random.shuffle(self.roles)
|
|
|
|
random.shuffle(self.roles)
|
|
|
|
self.players.sort(key=lambda pl: pl.member.display_name.lower())
|
|
|
|
self.players.sort(key=lambda pl: pl.member.display_name.lower())
|
|
|
|
|
|
|
|
|
|
|
|
if len(self.roles) != len(self.players):
|
|
|
|
if len(self.roles) != len(self.players):
|
|
|
|
await self.village_channel("Unhandled error - roles!=players")
|
|
|
|
await self.village_channel("Unhandled error - roles!=players")
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
for idx, role in enumerate(self.roles):
|
|
|
|
for idx, role in enumerate(self.roles):
|
|
|
|
self.roles[idx] = role(self)
|
|
|
|
self.roles[idx] = role(self)
|
|
|
|
await self.roles[idx].assign_player(self.players[idx])
|
|
|
|
await self.roles[idx].assign_player(self.players[idx])
|
|
|
|
# Sorted players, now assign id's
|
|
|
|
# Sorted players, now assign id's
|
|
|
|
await self.players[idx].assign_id(idx)
|
|
|
|
await self.players[idx].assign_id(idx)
|
|
|
|
|
|
|
|
|
|
|
|
async def get_player_by_member(self, member):
|
|
|
|
async def get_player_by_member(self, member):
|
|
|
|
for player in self.players:
|
|
|
|
for player in self.players:
|
|
|
|
if player.member == member:
|
|
|
|
if player.member == member:
|
|
|
|
return player
|
|
|
|
return player
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
async def dead_perms(self, channel, member):
|
|
|
|
async def dead_perms(self, channel, member):
|
|
|
|
await channel.set_permissions(member, read_messages=True, send_message=False, add_reactions=False)
|
|
|
|
await channel.set_permissions(member, read_messages=True, send_message=False, add_reactions=False)
|
|
|
|
|
|
|
|
|
|
|
|
async def night_perms(self, channel):
|
|
|
|
async def night_perms(self, channel):
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False, send_messages=False)
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False, send_messages=False)
|
|
|
|
|
|
|
|
|
|
|
|
async def day_perms(self, channel):
|
|
|
|
async def day_perms(self, channel):
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False)
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False)
|
|
|
|
|
|
|
|
|
|
|
|
async def speech_perms(self, channel, member, undo=False):
|
|
|
|
async def speech_perms(self, channel, member, undo=False):
|
|
|
|
if undo:
|
|
|
|
if undo:
|
|
|
|
await channel.set_permissions(member, read_messages=True)
|
|
|
|
await channel.set_permissions(member, read_messages=True)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False, send_messages=False)
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False, send_messages=False)
|
|
|
|
await channel.set_permissions(member, read_messages=True, send_messages=True)
|
|
|
|
await channel.set_permissions(member, read_messages=True, send_messages=True)
|
|
|
|
|
|
|
|
|
|
|
|
async def normal_perms(self, channel, member_list):
|
|
|
|
async def normal_perms(self, channel, member_list):
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False)
|
|
|
|
await channel.set_permissions(self.guild.default_role, read_messages=False)
|
|
|
|
for member in member_list:
|
|
|
|
for member in member_list:
|
|
|
|
await channel.set_permissions(member, read_messages=True)
|
|
|
|
await channel.set_permissions(member, read_messages=True)
|
|
|
|
|
|
|
|
|
|
|
|
async def _check_game_over(self):
|
|
|
|
async def _check_game_over(self):
|
|
|
|
# ToDo
|
|
|
|
# ToDo
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|