fight-fixes
Bobloy 7 years ago
parent e03c32926e
commit 6e87f41dcc

@ -2,4 +2,4 @@ from .werewolf import Werewolf
def setup(bot): def setup(bot):
bot.add_cog(Werewolf(bot)) bot.add_cog(Werewolf(bot))

@ -7,7 +7,7 @@ from werewolf.roles.villager import Villager
from werewolf.roles.seer import Seer from werewolf.roles.seer import Seer
# All roles in this list for iterating # All roles in this list for iterating
role_list = [Villager, VanillaWerewolf] role_list = [Villager, VanillaWerewolf]
""" """
Example code: Example code:
@ -28,7 +28,7 @@ double digit position preempted by `-`
async def parse_code(code): async def parse_code(code):
"""Do the magic described above""" """Do the magic described above"""
out = [] out = []
decode = code.copy() # for now, pass exact names decode = code.copy() # for now, pass exact names
for role_id in decode: for role_id in decode:
print(role_id) print(role_id)
if role_id == "Villager": if role_id == "Villager":
@ -40,7 +40,7 @@ async def parse_code(code):
else: # Fail to parse else: # Fail to parse
return None return None
out.append(role) out.append(role)
return out return out
@ -48,6 +48,6 @@ async def build_game(channel: discord.TextChannel):
await channel.send("Not currently available") await channel.send("Not currently available")
code = 12345678 code = 12345678
await channel.send("Your game code is **`{}`**".format(code)) await channel.send("Your game code is **`{}`**".format(code))
# Make this embeds # Make this embeds

@ -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

@ -1,10 +1,23 @@
{ {
"author" : ["Bobloy"], "author": [
"bot_version" : [3,0,0], "Bobloy"
"description" : "Customizable Werewolf Game", ],
"hidden" : false, "bot_version": [
"install_msg" : "Thank you for installing Werewolf! Use [p]wwset to run inital setup", 3,
"requirements" : [], 0,
"short" : "Werewolf Game", 0
"tags" : ["mafia", "werewolf", "party", "fun", "game", "bobloy"] ],
"description": "Customizable Werewolf Game",
"hidden": false,
"install_msg": "Thank you for installing Werewolf! Use [p]wwset to run inital setup",
"requirements": [],
"short": "Werewolf Game",
"tags": [
"mafia",
"werewolf",
"party",
"fun",
"game",
"bobloy"
]
} }

@ -11,7 +11,7 @@ class Player:
self.mention = member.mention self.mention = member.mention
self.role = None self.role = None
self.id = None self.id = None
self.alive = True self.alive = True
self.muted = False self.muted = False
self.protected = False self.protected = False
@ -22,9 +22,9 @@ class Player:
""" """
role.player = self role.player = self
self.role = role self.role = role
async def assign_id(self, target_id): async def assign_id(self, target_id):
self.id = target_id self.id = target_id
async def send_dm(self, message): async def send_dm(self, message):
await self.member.send(message) # Lets do embeds later await self.member.send(message) # Lets do embeds later

@ -35,24 +35,24 @@ class Role:
5. Disruptive actions (Killing) 5. Disruptive actions (Killing)
6. Role altering actions (Cult / Mason) 6. Role altering actions (Cult / Mason)
""" """
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles) rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [0] # List of enrolled categories (listed above) category = [0] # List of enrolled categories (listed above)
alignment = 0 # 1: Town, 2: Werewolf, 3: Neutral alignment = 0 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game unique = False # Only one of this role per game
game_start_message = ( game_start_message = (
"Your role is **Default**\n" "Your role is **Default**\n"
"You win by testing the game\n" "You win by testing the game\n"
"Lynch players during the day with `[p]ww vote <ID>`" "Lynch players during the day with `[p]ww vote <ID>`"
) )
def __init__(self, game): def __init__(self, game):
self.game = game self.game = game
self.player = None self.player = None
self.blocked = False self.blocked = False
self.properties = {} # Extra data for other roles (i.e. arsonist) self.properties = {} # Extra data for other roles (i.e. arsonist)
self.action_list = [ self.action_list = [
(self._at_game_start, 1), # (Action, Priority) (self._at_game_start, 1), # (Action, Priority)
(self._at_day_start, 0), (self._at_day_start, 0),
@ -63,13 +63,13 @@ class Role:
(self._at_night_start, 0), (self._at_night_start, 0),
(self._at_night_end, 0), (self._at_night_end, 0),
(self._at_visit, 0) (self._at_visit, 0)
] ]
async def on_event(self, event, data): async def on_event(self, event, data):
""" """
See Game class for event guide See Game class for event guide
""" """
await self.action_list[event][0](data) await self.action_list[event][0](data)
async def assign_player(self, player): async def assign_player(self, player):
@ -80,7 +80,7 @@ class Role:
player.role = self player.role = self
self.player = player self.player = player
async def get_alignment(self, source=None): async def get_alignment(self, source=None):
""" """
Interaction for powerful access of alignment Interaction for powerful access of alignment
@ -88,58 +88,58 @@ class Role:
Unlikely to be able to deceive this Unlikely to be able to deceive this
""" """
return self.alignment return self.alignment
async def see_alignment(self, source=None): async def see_alignment(self, source=None):
""" """
Interaction for investigative roles attempting Interaction for investigative roles attempting
to see alignment (Village, Werewolf Other) to see alignment (Village, Werewolf Other)
""" """
return "Other" return "Other"
async def get_role(self, source=None): async def get_role(self, source=None):
""" """
Interaction for powerful access of role Interaction for powerful access of role
Unlikely to be able to deceive this Unlikely to be able to deceive this
""" """
return "Default" return "Default"
async def see_role(self, source=None): async def see_role(self, source=None):
""" """
Interaction for investigative roles. Interaction for investigative roles.
More common to be able to deceive this action More common to be able to deceive this action
""" """
return "Role" return "Role"
async def _at_game_start(self, data=None): async def _at_game_start(self, data=None):
if self.channel_id: if self.channel_id:
await self.game.register_channel(self.channel_id, self) await self.game.register_channel(self.channel_id, self)
await self.player.send_dm(self.game_start_message) #Maybe embeds eventually await self.player.send_dm(self.game_start_message) # Maybe embeds eventually
async def _at_day_start(self, data=None): async def _at_day_start(self, data=None):
pass pass
async def _at_voted(self, data=None): async def _at_voted(self, data=None):
pass pass
async def _at_kill(self, data=None): async def _at_kill(self, data=None):
pass pass
async def _at_hang(self, data=None): async def _at_hang(self, data=None):
pass pass
async def _at_day_end(self, data=None): async def _at_day_end(self, data=None):
pass pass
async def _at_night_start(self, data=None): async def _at_night_start(self, data=None):
pass pass
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
pass pass
async def _at_visit(self, data=None): async def _at_visit(self, data=None):
pass pass
async def kill(self, source): async def kill(self, source):
""" """
Called when someone is trying to kill you! Called when someone is trying to kill you!

@ -1,18 +1,18 @@
from werewolf.role import Role from werewolf.role import Role
class Seer(Role): class Seer(Role):
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles) rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [1,2] # List of enrolled categories (listed above) category = [1, 2] # List of enrolled categories (listed above)
alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game unique = False # Only one of this role per game
game_start_message=( game_start_message = (
"Your role is **Seer**\n" "Your role is **Seer**\n"
"You win by lynching all evil in the town\n" "You win by lynching all evil in the town\n"
"Lynch players during the day with `[p]ww vote <ID>`\n" "Lynch players during the day with `[p]ww vote <ID>`\n"
"Check for werewolves at night with `[p]ww choose <ID>`" "Check for werewolves at night with `[p]ww choose <ID>`"
) )
def __init__(self, game): def __init__(self, game):
super().__init__() super().__init__()
@ -30,32 +30,32 @@ class Seer(Role):
(self._at_day_end, 0), (self._at_day_end, 0),
(self._at_night_start, 2), (self._at_night_start, 2),
(self._at_night_end, 4) (self._at_night_end, 4)
] ]
# async def on_event(self, event, data): # async def on_event(self, event, data):
# """ # """
# See Game class for event guide # See Game class for event guide
# """ # """
#
# await self.action_list[event][0](data) # await self.action_list[event][0](data)
#
#
# async def assign_player(self, player): # async def assign_player(self, player):
# """ # """
# Give this role a player # Give this role a player
# Can be used after the game has started (Cult, Mason, other role swap) # Can be used after the game has started (Cult, Mason, other role swap)
# """ # """
#
# player.role = self # player.role = self
# self.player = player # self.player = player
#
# async def get_alignment(self, source=None): # async def get_alignment(self, source=None):
# """ # """
# Interaction for power access of team (Village, Werewolf, Other) # Interaction for power access of team (Village, Werewolf, Other)
# Unlikely to be able to deceive this # Unlikely to be able to deceive this
# """ # """
# return self.alignment # return self.alignment
async def see_alignment(self, source=None): async def see_alignment(self, source=None):
""" """
Interaction for investigative roles attempting Interaction for investigative roles attempting
@ -69,44 +69,43 @@ class Seer(Role):
Unlikely to be able to deceive this Unlikely to be able to deceive this
""" """
return "Villager" return "Villager"
async def _see_role(self, source=None): async def _see_role(self, source=None):
""" """
Interaction for investigative roles. Interaction for investigative roles.
More common to be able to deceive these roles More common to be able to deceive these roles
""" """
return "Villager" return "Villager"
# async def _at_game_start(self, data=None): # async def _at_game_start(self, data=None):
# pass # pass
#
# async def _at_day_start(self, data=None): # async def _at_day_start(self, data=None):
# pass # pass
#
# async def _at_voted(self, target=None): # async def _at_voted(self, target=None):
# pass # pass
#
# async def _at_kill(self, target=None): # async def _at_kill(self, target=None):
# pass # pass
#
# async def _at_hang(self, target=None): # async def _at_hang(self, target=None):
# pass # pass
#
# async def _at_day_end(self): # async def _at_day_end(self):
# pass # pass
async def _at_night_start(self, data=None): async def _at_night_start(self, data=None):
await self.game.generate_targets(self.player.member) await self.game.generate_targets(self.player.member)
await self.player.send_dm("{}\n**Pick a target to see tonight**\n") await self.player.send_dm("{}\n**Pick a target to see tonight**\n")
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
target = await self.game.visit(self.see_target) target = await self.game.visit(self.see_target)
alignment = None alignment = None
if target: if target:
alignment = await target.see_alignment(self.player) alignment = await target.see_alignment(self.player)
if alignment == "Werewolf": if alignment == "Werewolf":
out = "Your insight reveals this player to be a **Werewolf!**" out = "Your insight reveals this player to be a **Werewolf!**"
else: else:
@ -115,23 +114,23 @@ class Seer(Role):
await self.player.send_dm(out) await self.player.send_dm(out)
# async def _at_visit(self, data=None): # async def _at_visit(self, data=None):
# pass # pass
#
# async def kill(self, source): # async def kill(self, source):
# """ # """
# Called when someone is trying to kill you! # Called when someone is trying to kill you!
# Can you do anything about it? # Can you do anything about it?
# self.alive is now set to False, set to True to stay alive # self.alive is now set to False, set to True to stay alive
# """ # """
# pass # pass
#
# async def visit(self, source): # async def visit(self, source):
# """ # """
# Called whenever a night action targets you # Called whenever a night action targets you
# Source is the player who visited you # Source is the player who visited you
# """ # """
# pass # pass
async def choose(self, ctx, data): async def choose(self, ctx, data):
"""Handle night actions""" """Handle night actions"""
id = int(data) id = int(data)
@ -139,10 +138,10 @@ class Seer(Role):
target = self.game.players[id] target = self.game.players[id]
except IndexError: except IndexError:
target = None target = None
if target is None: if target is None:
await ctx.send("Not a valid ID") await ctx.send("Not a valid ID")
return return
self.see_target = id self.see_target = id
await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name)) await ctx.send("**You will attempt to see the role of {} tonight...**".format(target.member.display_name))

@ -4,10 +4,9 @@ from werewolf.votegroups.wolfvote import WolfVote
class VanillaWerewolf(Role): class VanillaWerewolf(Role):
rand_choice = True rand_choice = True
category = [11, 15] category = [11, 15]
alignment = 2 # 1: Town, 2: Werewolf, 3: Neutral alignment = 2 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "werewolves" channel_id = "werewolves"
unique = False unique = False
game_start_message = ( game_start_message = (
@ -15,13 +14,11 @@ class VanillaWerewolf(Role):
"You win by killing everyone else in the village\n" "You win by killing everyone else in the village\n"
"Lynch players during the day with `[p]ww vote <ID>`\n" "Lynch players during the day with `[p]ww vote <ID>`\n"
"Vote to kill players at night with `[p]ww vote <ID>`" "Vote to kill players at night with `[p]ww vote <ID>`"
) )
def __init__(self, game): def __init__(self, game):
super().__init__(game) super().__init__(game)
self.action_list = [ self.action_list = [
(self._at_game_start, 1), # (Action, Priority) (self._at_game_start, 1), # (Action, Priority)
(self._at_day_start, 0), (self._at_day_start, 0),
@ -32,98 +29,97 @@ class VanillaWerewolf(Role):
(self._at_night_start, 0), (self._at_night_start, 0),
(self._at_night_end, 0), (self._at_night_end, 0),
(self._at_visit, 0) (self._at_visit, 0)
] ]
# async def on_event(self, event, data): # async def on_event(self, event, data):
# """ # """
# See Game class for event guide # See Game class for event guide
# """ # """
# await self.action_list[event][0](data) # await self.action_list[event][0](data)
# async def assign_player(self, player): # async def assign_player(self, player):
# """ # """
# Give this role a player # Give this role a player
# Can be used after the game has started (Cult, Mason, role swap) # Can be used after the game has started (Cult, Mason, role swap)
# """ # """
# player.role = self # player.role = self
# self.player = player # self.player = player
# async def get_alignment(self, source=None): # async def get_alignment(self, source=None):
# """ # """
# Interaction for power access of team (Village, Werewolf, Other) # Interaction for power access of team (Village, Werewolf, Other)
# Unlikely to be able to deceive this # Unlikely to be able to deceive this
# """ # """
# return self.alignment # return self.alignment
async def see_alignment(self, source=None): async def see_alignment(self, source=None):
""" """
Interaction for investigative roles attempting Interaction for investigative roles attempting
to see team (Village, Werewolf Other) to see team (Village, Werewolf Other)
""" """
return "Werewolf" return "Werewolf"
async def _get_role(self, source=None): async def _get_role(self, source=None):
""" """
Interaction for powerful access of role Interaction for powerful access of role
Unlikely to be able to deceive this Unlikely to be able to deceive this
""" """
return "Werewolf" return "Werewolf"
async def _see_role(self, source=None): async def _see_role(self, source=None):
""" """
Interaction for investigative roles. Interaction for investigative roles.
More common to be able to deceive these roles More common to be able to deceive these roles
""" """
return "Werewolf" return "Werewolf"
async def _at_game_start(self, data=None): async def _at_game_start(self, data=None):
if self.channel_id: if self.channel_id:
print("Wolf has channel_id: "+self.channel_id) print("Wolf has channel_id: " + self.channel_id)
await self.game.register_channel(self.channel_id, self, WolfVote) # Add VoteGroup WolfVote await self.game.register_channel(self.channel_id, self, WolfVote) # Add VoteGroup WolfVote
await self.player.send_dm(self.game_start_message) await self.player.send_dm(self.game_start_message)
# async def _at_day_start(self, data=None): # async def _at_day_start(self, data=None):
# super()._at_day_start(data) # super()._at_day_start(data)
# async def _at_voted(self, data=None): # async def _at_voted(self, data=None):
# super()._at_voted(data) # super()._at_voted(data)
# async def _at_kill(self, data=None): # async def _at_kill(self, data=None):
# super()._at_kill(data) # super()._at_kill(data)
# async def _at_hang(self, data=None): # async def _at_hang(self, data=None):
# super()._at_hang(data) # super()._at_hang(data)
# async def _at_day_end(self, data=None): # async def _at_day_end(self, data=None):
# super()._at_day_end(data) # super()._at_day_end(data)
# async def _at_night_start(self, data=None): # async def _at_night_start(self, data=None):
# super()._at_night_start(data) # super()._at_night_start(data)
# async def _at_night_end(self, data=None): # async def _at_night_end(self, data=None):
# super()._at_night_end(data) # super()._at_night_end(data)
# async def _at_visit(self, data=None): # async def _at_visit(self, data=None):
# pass # pass
# async def kill(self, source): # async def kill(self, source):
# """ # """
# Called when someone is trying to kill you! # Called when someone is trying to kill you!
# Can you do anything about it? # Can you do anything about it?
# self.alive is now set to False, set to True to stay alive # self.alive is now set to False, set to True to stay alive
# """ # """
# pass # pass
# async def visit(self, source): # async def visit(self, source):
# """ # """
# Called whenever a night action targets you # Called whenever a night action targets you
# Source is the player who visited you # Source is the player who visited you
# """ # """
# pass # pass
async def choose(self, ctx, data): async def choose(self, ctx, data):
"""Handle night actions""" """Handle night actions"""

@ -1,17 +1,17 @@
from werewolf.role import Role from werewolf.role import Role
class Villager(Role): class Villager(Role):
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles) rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [1] # List of enrolled categories (listed above) category = [1] # List of enrolled categories (listed above)
alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game unique = False # Only one of this role per game
game_start_message=( game_start_message = (
"Your role is **Villager**\n" "Your role is **Villager**\n"
"You win by lynching all evil in the town\n" "You win by lynching all evil in the town\n"
"Lynch players during the day with `[p]ww vote <ID>`" "Lynch players during the day with `[p]ww vote <ID>`"
) )
def __init__(self, game): def __init__(self, game):
super().__init__() super().__init__()
@ -19,43 +19,43 @@ class Villager(Role):
# self.player = None # self.player = None
# self.blocked = False # self.blocked = False
# self.properties = {} # Extra data for other roles (i.e. arsonist) # self.properties = {} # Extra data for other roles (i.e. arsonist)
#
# self.action_list = [ # self.action_list = [
# (self._at_game_start, 0), # (Action, Priority) # (self._at_game_start, 0), # (Action, Priority)
# (self._at_day_start, 0), # (self._at_day_start, 0),
# (self._at_voted, 0), # (self._at_voted, 0),
# (self._at_kill, 0), # (self._at_kill, 0),
# (self._at_hang, 0), # (self._at_hang, 0),
# (self._at_day_end, 0), # (self._at_day_end, 0),
# (self._at_night_start, 0), # (self._at_night_start, 0),
# (self._at_night_end, 0), # (self._at_night_end, 0),
# (self._at_visit, 0) # (self._at_visit, 0)
# ] # ]
# async def on_event(self, event, data): # async def on_event(self, event, data):
# """ # """
# See Game class for event guide # See Game class for event guide
# """ # """
#
# await self.action_list[event][0](data) # await self.action_list[event][0](data)
#
#
# async def assign_player(self, player): # async def assign_player(self, player):
# """ # """
# Give this role a player # Give this role a player
# Can be used after the game has started (Cult, Mason, other role swap) # Can be used after the game has started (Cult, Mason, other role swap)
# """ # """
#
# player.role = self # player.role = self
# self.player = player # self.player = player
#
# async def get_alignment(self, source=None): # async def get_alignment(self, source=None):
# """ # """
# Interaction for power access of team (Village, Werewolf, Other) # Interaction for power access of team (Village, Werewolf, Other)
# Unlikely to be able to deceive this # Unlikely to be able to deceive this
# """ # """
# return self.alignment # return self.alignment
async def see_alignment(self, source=None): async def see_alignment(self, source=None):
""" """
Interaction for investigative roles attempting Interaction for investigative roles attempting
@ -69,56 +69,56 @@ class Villager(Role):
Unlikely to be able to deceive this Unlikely to be able to deceive this
""" """
return "Villager" return "Villager"
async def _see_role(self, source=None): async def _see_role(self, source=None):
""" """
Interaction for investigative roles. Interaction for investigative roles.
More common to be able to deceive these roles More common to be able to deceive these roles
""" """
return "Villager" return "Villager"
# async def _at_game_start(self, data=None): # async def _at_game_start(self, data=None):
# pass # pass
#
# async def _at_day_start(self, data=None): # async def _at_day_start(self, data=None):
# pass # pass
#
# async def _at_voted(self, target=None): # async def _at_voted(self, target=None):
# pass # pass
#
# async def _at_kill(self, target=None): # async def _at_kill(self, target=None):
# pass # pass
#
# async def _at_hang(self, target=None): # async def _at_hang(self, target=None):
# pass # pass
#
# async def _at_day_end(self): # async def _at_day_end(self):
# pass # pass
#
# async def _at_night_start(self): # async def _at_night_start(self):
# pass # pass
#
# async def _at_night_end(self): # async def _at_night_end(self):
# pass # pass
#
# async def _at_visit(self, data=None): # async def _at_visit(self, data=None):
# pass # pass
#
# async def kill(self, source): # async def kill(self, source):
# """ # """
# Called when someone is trying to kill you! # Called when someone is trying to kill you!
# Can you do anything about it? # Can you do anything about it?
# self.alive is now set to False, set to True to stay alive # self.alive is now set to False, set to True to stay alive
# """ # """
# pass # pass
#
# async def visit(self, source): # async def visit(self, source):
# """ # """
# Called whenever a night action targets you # Called whenever a night action targets you
# Source is the player who visited you # Source is the player who visited you
# """ # """
# pass # pass
#
# async def choose(self, ctx, data): # async def choose(self, ctx, data):
# """Handle night actions""" # """Handle night actions"""
# pass # pass

@ -3,9 +3,9 @@ class VoteGroup:
Base VoteGroup class for werewolf game Base VoteGroup class for werewolf game
Handles secret channels and group decisions Handles secret channels and group decisions
""" """
alignment = 0 # 1: Town, 2: Werewolf, 3: Neutral alignment = 0 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" channel_id = ""
def __init__(self, game, channel): def __init__(self, game, channel):
self.game = game self.game = game
@ -13,7 +13,7 @@ class VoteGroup:
self.players = [] self.players = []
self.vote_results = {} self.vote_results = {}
self.properties = {} # Extra data for other options self.properties = {} # Extra data for other options
self.action_list = [ self.action_list = [
(self._at_game_start, 0), # (Action, Priority) (self._at_game_start, 0), # (Action, Priority)
(self._at_day_start, 0), (self._at_day_start, 0),
@ -24,13 +24,13 @@ class VoteGroup:
(self._at_night_start, 2), (self._at_night_start, 2),
(self._at_night_end, 0), (self._at_night_end, 0),
(self._at_visit, 0) (self._at_visit, 0)
] ]
async def on_event(self, event, data): async def on_event(self, event, data):
""" """
See Game class for event guide See Game class for event guide
""" """
await self.action_list[event][0](data) await self.action_list[event][0](data)
async def _at_game_start(self, data=None): async def _at_game_start(self, data=None):
@ -38,41 +38,41 @@ class VoteGroup:
async def _at_day_start(self, data=None): async def _at_day_start(self, data=None):
pass pass
async def _at_voted(self, data=None): async def _at_voted(self, data=None):
pass pass
async def _at_kill(self, data=None): async def _at_kill(self, data=None):
if data["player"] in self.players: if data["player"] in self.players:
self.players.pop(data["player"]) self.players.pop(data["player"])
async def _at_hang(self, data=None): async def _at_hang(self, data=None):
if data["player"] in self.players: if data["player"] in self.players:
self.players.pop(data["player"]) self.players.pop(data["player"])
async def _at_day_end(self, data=None): async def _at_day_end(self, data=None):
pass pass
async def _at_night_start(self, data=None): async def _at_night_start(self, data=None):
if self.channel is None: if self.channel is None:
return return
await self.game.generate_targets(self.channel) await self.game.generate_targets(self.channel)
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
if self.channel is None: if self.channel is None:
return return
target = None target = None
vote_list = list(self.vote_results.values()) vote_list = list(self.vote_results.values())
if vote_list: if vote_list:
target = max(set(vote_list), key=vote_list.count) target = max(set(vote_list), key=vote_list.count)
if target: if target:
# Do what you voted on # Do what you voted on
pass pass
async def _at_visit(self, data=None): async def _at_visit(self, data=None):
pass pass
@ -81,7 +81,7 @@ class VoteGroup:
Extend players by passed list Extend players by passed list
""" """
self.players.extend(players) self.players.extend(players)
async def remove_player(self, player): async def remove_player(self, player):
""" """
Remove a player from player list Remove a player from player list
@ -93,5 +93,5 @@ class VoteGroup:
""" """
Receive vote from game Receive vote from game
""" """
self.vote_results[author.id] = id self.vote_results[author.id] = id

@ -7,14 +7,14 @@ class WolfVote(VoteGroup):
""" """
Werewolf implementation of base VoteGroup class Werewolf implementation of base VoteGroup class
""" """
alignment = 2 # 1: Town, 2: Werewolf, 3: Neutral alignment = 2 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "werewolves" channel_id = "werewolves"
kill_messages = [ kill_messages = [
"**{ID}** - {target} was mauled by wolves", "**{ID}** - {target} was mauled by wolves",
"**{ID}** - {target} was found torn to shreds"] "**{ID}** - {target} was found torn to shreds"]
def __init__(self, game, channel): def __init__(self, game, channel):
super().__init__(game, channel) super().__init__(game, channel)
# self.game = game # self.game = game
@ -35,9 +35,10 @@ class WolfVote(VoteGroup):
(self._at_night_start, 2), (self._at_night_start, 2),
(self._at_night_end, 5), # Kill priority (self._at_night_end, 5), # Kill priority
(self._at_visit, 0) (self._at_visit, 0)
] ]
# async def on_event(self, event, data): # async def on_event(self, event, data):
# """ # """
# See Game class for event guide # See Game class for event guide
# """ # """
@ -63,24 +64,24 @@ class WolfVote(VoteGroup):
# #
# async def _at_day_end(self, data=None): # async def _at_day_end(self, data=None):
# pass # pass
async def _at_night_start(self, data=None): async def _at_night_start(self, data=None):
if self.channel is None: if self.channel is None:
return return
await self.game.generate_targets(self.channel) await self.game.generate_targets(self.channel)
await self.channel.send(" ".join(player.mention for player in self.players)) await self.channel.send(" ".join(player.mention for player in self.players))
self.killer = random.choice(self.players) self.killer = random.choice(self.players)
await self.channel.send("{} has been selected as tonight's killer".format(self.killer.member.display_name)) await self.channel.send("{} has been selected as tonight's killer".format(self.killer.member.display_name))
async def _at_night_end(self, data=None): async def _at_night_end(self, data=None):
if self.channel is None: if self.channel is None:
return return
target_id = None target_id = None
vote_list = list(self.vote_results.values()) vote_list = list(self.vote_results.values())
if vote_list: if vote_list:
target_id = max(set(vote_list), key=vote_list.count) target_id = max(set(vote_list), key=vote_list.count)
@ -90,7 +91,7 @@ class WolfVote(VoteGroup):
await self.channel.send("**{} has left to complete the kill...**".format(self.killer.member.display_name)) await self.channel.send("**{} has left to complete the kill...**".format(self.killer.member.display_name))
else: else:
await self.channel.send("**No kill will be attempted tonight...**") await self.channel.send("**No kill will be attempted tonight...**")
# async def _at_visit(self, data=None): # async def _at_visit(self, data=None):
# pass # pass
# #
@ -111,7 +112,7 @@ class WolfVote(VoteGroup):
""" """
Receive vote from game Receive vote from game
""" """
self.vote_results[author.id] = target_id self.vote_results[author.id] = target_id
await self.channel.send("{} has voted to kill {}".format(author.mention, target.member.display_name)) await self.channel.send("{} has voted to kill {}".format(author.mention, target.member.display_name))

@ -16,11 +16,11 @@ class Werewolf:
default_global = {} default_global = {}
default_guild = { default_guild = {
"role": None "role": None
} }
self.config.register_global(**default_global) self.config.register_global(**default_global)
self.config.register_guild(**default_guild) self.config.register_guild(**default_guild)
self.games = {} # Active games stored here, id is per guild self.games = {} # Active games stored here, id is per guild
@commands.group() @commands.group()
@ -48,16 +48,16 @@ class Werewolf:
""" """
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send_help() await ctx.send_help()
@commands.guild_only() @commands.guild_only()
@ww.command() @ww.command()
async def new(self, ctx, game_code): async def new(self, ctx, game_code):
""" """
Create and join a new game of Werewolf Create and join a new game of Werewolf
""" """
game = self._get_game(ctx.guild, game_code) game = self._get_game(ctx.guild, game_code)
if not game: if not game:
await ctx.send("Failed to start a new game") await ctx.send("Failed to start a new game")
else: else:
@ -69,26 +69,26 @@ class Werewolf:
""" """
Joins a game of Werewolf Joins a game of Werewolf
""" """
game = self._get_game(ctx.guild) game = self._get_game(ctx.guild)
if not game: if not game:
await ctx.send("No game to join!\nCreate a new one with `[p]ww new`") await ctx.send("No game to join!\nCreate a new one with `[p]ww new`")
return return
await game.join(ctx.author, ctx.channel) await game.join(ctx.author, ctx.channel)
@commands.guild_only() @commands.guild_only()
@ww.command() @ww.command()
async def quit(self, ctx): async def quit(self, ctx):
""" """
Quit a game of Werewolf Quit a game of Werewolf
""" """
game = self._get_game(ctx.guild) game = self._get_game(ctx.guild)
await game.quit(ctx.author, ctx.channel) await game.quit(ctx.author, ctx.channel)
@commands.guild_only() @commands.guild_only()
@ww.command() @ww.command()
async def start(self, ctx): async def start(self, ctx):
@ -98,9 +98,9 @@ class Werewolf:
game = self._get_game(ctx.guild) game = self._get_game(ctx.guild)
if not game: if not game:
await ctx.send("No game running, cannot start") await ctx.send("No game running, cannot start")
await game.setup(ctx) await game.setup(ctx)
@commands.guild_only() @commands.guild_only()
@ww.command() @ww.command()
async def stop(self, ctx): async def stop(self, ctx):
@ -110,10 +110,10 @@ class Werewolf:
game = self._get_game(ctx.guild) game = self._get_game(ctx.guild)
if not game: if not game:
await ctx.send("No game running, cannot stop") await ctx.send("No game running, cannot stop")
game.game_over = True game.game_over = True
@commands.guild_only() @commands.guild_only()
@ww.command() @ww.command()
async def vote(self, ctx, id: int): async def vote(self, ctx, id: int):
""" """
@ -123,31 +123,31 @@ class Werewolf:
id = int(id) id = int(id)
except: except:
id = None id = None
if id is None: if id is None:
await ctx.send("`id` must be an integer") await ctx.send("`id` must be an integer")
return return
# if ctx.guild is None: # if ctx.guild is None:
# # DM nonsense, find their game # # DM nonsense, find their game
# # If multiple games, panic # # If multiple games, panic
# for game in self.games.values(): # for game in self.games.values():
# if await game.get_player_by_member(ctx.author): # if await game.get_player_by_member(ctx.author):
# break #game = game # break #game = game
# else: # else:
# await ctx.send("You're not part of any werewolf game") # await ctx.send("You're not part of any werewolf game")
# return # return
# else: # else:
game = self._get_game(ctx.guild) game = self._get_game(ctx.guild)
if game is None: if game is None:
await ctx.send("No game running, cannot vote") await ctx.send("No game running, cannot vote")
return return
# Game handles response now # Game handles response now
channel = ctx.channel channel = ctx.channel
if channel == game.village_channel: if channel == game.village_channel:
await game.vote(ctx.author, id, channel) await game.vote(ctx.author, id, channel)
elif channel in (c["channel"] for c in game.p_channels.values()): elif channel in (c["channel"] for c in game.p_channels.values()):
await game.vote(ctx.author, id, channel) await game.vote(ctx.author, id, channel)
@ -165,7 +165,7 @@ class Werewolf:
if ctx.guild is not None: if ctx.guild is not None:
await ctx.send("This action is only available in DM's") await ctx.send("This action is only available in DM's")
return return
# DM nonsense, find their game # DM nonsense, find their game
# If multiple games, panic # If multiple games, panic
for game in self.games.values(): for game in self.games.values():
@ -176,7 +176,7 @@ class Werewolf:
return return
await game.choose(ctx, data) await game.choose(ctx, data)
def _get_game(self, guild, game_code=None): def _get_game(self, guild, game_code=None):
if guild is None: if guild is None:
# Private message, can't get guild # Private message, can't get guild

Loading…
Cancel
Save