Black formatting
This commit is contained in:
parent
7a9fb922bd
commit
339492d6d9
@ -17,7 +17,7 @@ from redbot.core.utils.menus import menu, prev_page, next_page, close_menu
|
|||||||
|
|
||||||
ROLE_LIST = sorted([Villager, Seer, VanillaWerewolf], key=lambda x: x.alignment)
|
ROLE_LIST = sorted([Villager, Seer, VanillaWerewolf], key=lambda x: x.alignment)
|
||||||
|
|
||||||
ALIGNMENT_COLORS = [0x008000, 0xff0000, 0xc0c0c0]
|
ALIGNMENT_COLORS = [0x008000, 0xFF0000, 0xC0C0C0]
|
||||||
TOWN_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment == 1]
|
TOWN_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment == 1]
|
||||||
WW_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment == 2]
|
WW_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment == 2]
|
||||||
OTHER_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment not in [0, 1]]
|
OTHER_ROLES = [(idx, role) for idx, role in enumerate(ROLE_LIST) if role.alignment not in [0, 1]]
|
||||||
@ -26,21 +26,38 @@ ROLE_PAGES = []
|
|||||||
PAGE_GROUPS = [0]
|
PAGE_GROUPS = [0]
|
||||||
|
|
||||||
ROLE_CATEGORIES = {
|
ROLE_CATEGORIES = {
|
||||||
1: "Random", 2: "Investigative", 3: "Protective", 4: "Government",
|
1: "Random",
|
||||||
5: "Killing", 6: "Power (Special night action)",
|
2: "Investigative",
|
||||||
11: "Random", 12: "Deception", 15: "Killing", 16: "Support",
|
3: "Protective",
|
||||||
21: "Benign", 22: "Evil", 23: "Killing"}
|
4: "Government",
|
||||||
|
5: "Killing",
|
||||||
|
6: "Power (Special night action)",
|
||||||
|
11: "Random",
|
||||||
|
12: "Deception",
|
||||||
|
15: "Killing",
|
||||||
|
16: "Support",
|
||||||
|
21: "Benign",
|
||||||
|
22: "Evil",
|
||||||
|
23: "Killing",
|
||||||
|
}
|
||||||
|
|
||||||
CATEGORY_COUNT = []
|
CATEGORY_COUNT = []
|
||||||
|
|
||||||
|
|
||||||
def role_embed(idx, role, color):
|
def role_embed(idx, role, color):
|
||||||
embed = discord.Embed(title="**{}** - {}".format(idx, str(role.__name__)), description=role.game_start_message,
|
embed = discord.Embed(
|
||||||
color=color)
|
title="**{}** - {}".format(idx, str(role.__name__)),
|
||||||
embed.add_field(name='Alignment', value=['Town', 'Werewolf', 'Neutral'][role.alignment - 1], inline=True)
|
description=role.game_start_message,
|
||||||
embed.add_field(name='Multiples Allowed', value=str(not role.unique), inline=True)
|
color=color,
|
||||||
embed.add_field(name='Role Type', value=", ".join(ROLE_CATEGORIES[x] for x in role.category), inline=True)
|
)
|
||||||
embed.add_field(name='Random Option', value=str(role.rand_choice), inline=True)
|
embed.add_field(
|
||||||
|
name="Alignment", value=["Town", "Werewolf", "Neutral"][role.alignment - 1], inline=True
|
||||||
|
)
|
||||||
|
embed.add_field(name="Multiples Allowed", value=str(not role.unique), inline=True)
|
||||||
|
embed.add_field(
|
||||||
|
name="Role Type", value=", ".join(ROLE_CATEGORIES[x] for x in role.category), inline=True
|
||||||
|
)
|
||||||
|
embed.add_field(name="Random Option", value=str(role.rand_choice), inline=True)
|
||||||
|
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
@ -60,7 +77,11 @@ def setup():
|
|||||||
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
|
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
|
||||||
for k, v in ROLE_CATEGORIES.items():
|
for k, v in ROLE_CATEGORIES.items():
|
||||||
if 0 < k <= 6:
|
if 0 < k <= 6:
|
||||||
ROLE_PAGES.append(discord.Embed(title="RANDOM:Town Role", description="Town {}".format(v), color=0x008000))
|
ROLE_PAGES.append(
|
||||||
|
discord.Embed(
|
||||||
|
title="RANDOM:Town Role", description="Town {}".format(v), color=0x008000
|
||||||
|
)
|
||||||
|
)
|
||||||
CATEGORY_COUNT.append(k)
|
CATEGORY_COUNT.append(k)
|
||||||
|
|
||||||
# Random WW Roles
|
# Random WW Roles
|
||||||
@ -69,7 +90,12 @@ def setup():
|
|||||||
for k, v in ROLE_CATEGORIES.items():
|
for k, v in ROLE_CATEGORIES.items():
|
||||||
if 10 < k <= 16:
|
if 10 < k <= 16:
|
||||||
ROLE_PAGES.append(
|
ROLE_PAGES.append(
|
||||||
discord.Embed(title="RANDOM:Werewolf Role", description="Werewolf {}".format(v), color=0xff0000))
|
discord.Embed(
|
||||||
|
title="RANDOM:Werewolf Role",
|
||||||
|
description="Werewolf {}".format(v),
|
||||||
|
color=0xFF0000,
|
||||||
|
)
|
||||||
|
)
|
||||||
CATEGORY_COUNT.append(k)
|
CATEGORY_COUNT.append(k)
|
||||||
# Random Neutral Roles
|
# Random Neutral Roles
|
||||||
if len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
|
if len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
|
||||||
@ -77,7 +103,10 @@ def setup():
|
|||||||
for k, v in ROLE_CATEGORIES.items():
|
for k, v in ROLE_CATEGORIES.items():
|
||||||
if 20 < k <= 26:
|
if 20 < k <= 26:
|
||||||
ROLE_PAGES.append(
|
ROLE_PAGES.append(
|
||||||
discord.Embed(title="RANDOM:Neutral Role", description="Neutral {}".format(v), color=0xc0c0c0))
|
discord.Embed(
|
||||||
|
title="RANDOM:Neutral Role", description="Neutral {}".format(v), color=0xC0C0C0
|
||||||
|
)
|
||||||
|
)
|
||||||
CATEGORY_COUNT.append(k)
|
CATEGORY_COUNT.append(k)
|
||||||
|
|
||||||
|
|
||||||
@ -187,9 +216,15 @@ async def encode(roles, rand_roles):
|
|||||||
return out_code
|
return out_code
|
||||||
|
|
||||||
|
|
||||||
async def next_group(ctx: commands.Context, pages: list,
|
async def next_group(
|
||||||
controls: dict, message: discord.Message, page: int,
|
ctx: commands.Context,
|
||||||
timeout: float, emoji: str):
|
pages: list,
|
||||||
|
controls: dict,
|
||||||
|
message: discord.Message,
|
||||||
|
page: int,
|
||||||
|
timeout: float,
|
||||||
|
emoji: str,
|
||||||
|
):
|
||||||
perms = message.channel.permissions_for(ctx.me)
|
perms = message.channel.permissions_for(ctx.me)
|
||||||
if perms.manage_messages: # Can manage messages, so remove react
|
if perms.manage_messages: # Can manage messages, so remove react
|
||||||
try:
|
try:
|
||||||
@ -203,13 +238,18 @@ async def next_group(ctx: commands.Context, pages: list,
|
|||||||
else:
|
else:
|
||||||
page = PAGE_GROUPS[page]
|
page = PAGE_GROUPS[page]
|
||||||
|
|
||||||
return await menu(ctx, pages, controls, message=message,
|
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
|
||||||
page=page, timeout=timeout)
|
|
||||||
|
|
||||||
|
|
||||||
async def prev_group(ctx: commands.Context, pages: list,
|
async def prev_group(
|
||||||
controls: dict, message: discord.Message, page: int,
|
ctx: commands.Context,
|
||||||
timeout: float, emoji: str):
|
pages: list,
|
||||||
|
controls: dict,
|
||||||
|
message: discord.Message,
|
||||||
|
page: int,
|
||||||
|
timeout: float,
|
||||||
|
emoji: str,
|
||||||
|
):
|
||||||
perms = message.channel.permissions_for(ctx.me)
|
perms = message.channel.permissions_for(ctx.me)
|
||||||
if perms.manage_messages: # Can manage messages, so remove react
|
if perms.manage_messages: # Can manage messages, so remove react
|
||||||
try:
|
try:
|
||||||
@ -218,18 +258,23 @@ async def prev_group(ctx: commands.Context, pages: list,
|
|||||||
pass
|
pass
|
||||||
page = PAGE_GROUPS[bisect.bisect_left(PAGE_GROUPS, page) - 1]
|
page = PAGE_GROUPS[bisect.bisect_left(PAGE_GROUPS, page) - 1]
|
||||||
|
|
||||||
return await menu(ctx, pages, controls, message=message,
|
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
|
||||||
page=page, timeout=timeout)
|
|
||||||
|
|
||||||
|
|
||||||
def role_from_alignment(alignment):
|
def role_from_alignment(alignment):
|
||||||
return [role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
return [
|
||||||
for idx, role in enumerate(ROLE_LIST) if alignment == role.alignment]
|
role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
||||||
|
for idx, role in enumerate(ROLE_LIST)
|
||||||
|
if alignment == role.alignment
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def role_from_category(category):
|
def role_from_category(category):
|
||||||
return [role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
return [
|
||||||
for idx, role in enumerate(ROLE_LIST) if category in role.category]
|
role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
||||||
|
for idx, role in enumerate(ROLE_LIST)
|
||||||
|
if category in role.category
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def role_from_id(idx):
|
def role_from_id(idx):
|
||||||
@ -242,8 +287,11 @@ def role_from_id(idx):
|
|||||||
|
|
||||||
|
|
||||||
def role_from_name(name: str):
|
def role_from_name(name: str):
|
||||||
return [role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
return [
|
||||||
for idx, role in enumerate(ROLE_LIST) if name in role.__name__]
|
role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
|
||||||
|
for idx, role in enumerate(ROLE_LIST)
|
||||||
|
if name in role.__name__
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def say_role_list(code_list, rand_roles):
|
def say_role_list(code_list, rand_roles):
|
||||||
@ -268,7 +316,6 @@ def say_role_list(code_list, rand_roles):
|
|||||||
|
|
||||||
|
|
||||||
class GameBuilder:
|
class GameBuilder:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.code = []
|
self.code = []
|
||||||
self.rand_roles = []
|
self.rand_roles = []
|
||||||
@ -276,13 +323,13 @@ class GameBuilder:
|
|||||||
|
|
||||||
async def build_game(self, ctx: commands.Context):
|
async def build_game(self, ctx: commands.Context):
|
||||||
new_controls = {
|
new_controls = {
|
||||||
'⏪': prev_group,
|
"⏪": prev_group,
|
||||||
"⬅": prev_page,
|
"⬅": prev_page,
|
||||||
'☑': self.select_page,
|
"☑": self.select_page,
|
||||||
"➡": next_page,
|
"➡": next_page,
|
||||||
'⏩': next_group,
|
"⏩": next_group,
|
||||||
'📇': self.list_roles,
|
"📇": self.list_roles,
|
||||||
"❌": close_menu
|
"❌": close_menu,
|
||||||
}
|
}
|
||||||
|
|
||||||
await ctx.send("Browse through roles and add the ones you want using the check mark")
|
await ctx.send("Browse through roles and add the ones you want using the check mark")
|
||||||
@ -292,9 +339,16 @@ class GameBuilder:
|
|||||||
out = await encode(self.code, self.rand_roles)
|
out = await encode(self.code, self.rand_roles)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
async def list_roles(self, ctx: commands.Context, pages: list,
|
async def list_roles(
|
||||||
controls: dict, message: discord.Message, page: int,
|
self,
|
||||||
timeout: float, emoji: str):
|
ctx: commands.Context,
|
||||||
|
pages: list,
|
||||||
|
controls: dict,
|
||||||
|
message: discord.Message,
|
||||||
|
page: int,
|
||||||
|
timeout: float,
|
||||||
|
emoji: str,
|
||||||
|
):
|
||||||
perms = message.channel.permissions_for(ctx.me)
|
perms = message.channel.permissions_for(ctx.me)
|
||||||
if perms.manage_messages: # Can manage messages, so remove react
|
if perms.manage_messages: # Can manage messages, so remove react
|
||||||
try:
|
try:
|
||||||
@ -304,12 +358,18 @@ class GameBuilder:
|
|||||||
|
|
||||||
await ctx.send(embed=say_role_list(self.code, self.rand_roles))
|
await ctx.send(embed=say_role_list(self.code, self.rand_roles))
|
||||||
|
|
||||||
return await menu(ctx, pages, controls, message=message,
|
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
|
||||||
page=page, timeout=timeout)
|
|
||||||
|
|
||||||
async def select_page(self, ctx: commands.Context, pages: list,
|
async def select_page(
|
||||||
controls: dict, message: discord.Message, page: int,
|
self,
|
||||||
timeout: float, emoji: str):
|
ctx: commands.Context,
|
||||||
|
pages: list,
|
||||||
|
controls: dict,
|
||||||
|
message: discord.Message,
|
||||||
|
page: int,
|
||||||
|
timeout: float,
|
||||||
|
emoji: str,
|
||||||
|
):
|
||||||
perms = message.channel.permissions_for(ctx.me)
|
perms = message.channel.permissions_for(ctx.me)
|
||||||
if perms.manage_messages: # Can manage messages, so remove react
|
if perms.manage_messages: # Can manage messages, so remove react
|
||||||
try:
|
try:
|
||||||
@ -322,5 +382,4 @@ class GameBuilder:
|
|||||||
else:
|
else:
|
||||||
self.code.append(page)
|
self.code.append(page)
|
||||||
|
|
||||||
return await menu(ctx, pages, controls, message=message,
|
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
|
||||||
page=page, timeout=timeout)
|
|
||||||
|
250
werewolf/game.py
250
werewolf/game.py
@ -15,6 +15,7 @@ class Game:
|
|||||||
"""
|
"""
|
||||||
Base class to run a single game of Werewolf
|
Base class to run a single game of Werewolf
|
||||||
"""
|
"""
|
||||||
|
|
||||||
vote_groups: Dict[str, VoteGroup]
|
vote_groups: Dict[str, VoteGroup]
|
||||||
roles: List[Role]
|
roles: List[Role]
|
||||||
players: List[Player]
|
players: List[Player]
|
||||||
@ -22,19 +23,25 @@ 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 __init__(self, guild: discord.Guild, role: discord.Role = None,
|
def __init__(
|
||||||
category: discord.CategoryChannel = None, village: discord.TextChannel = None,
|
self,
|
||||||
log_channel: discord.TextChannel = None, game_code=None):
|
guild: discord.Guild,
|
||||||
|
role: discord.Role = None,
|
||||||
|
category: discord.CategoryChannel = None,
|
||||||
|
village: discord.TextChannel = None,
|
||||||
|
log_channel: discord.TextChannel = None,
|
||||||
|
game_code=None,
|
||||||
|
):
|
||||||
self.guild = guild
|
self.guild = guild
|
||||||
self.game_code = game_code
|
self.game_code = game_code
|
||||||
|
|
||||||
@ -97,22 +104,28 @@ class Game:
|
|||||||
await self.get_roles(ctx)
|
await self.get_roles(ctx)
|
||||||
|
|
||||||
if len(self.players) != len(self.roles):
|
if len(self.players) != len(self.roles):
|
||||||
await ctx.maybe_send_embed("Player count does not match role count, cannot start\n"
|
await ctx.maybe_send_embed(
|
||||||
"Currently **{} / {}**\n"
|
"Player count does not match role count, cannot start\n"
|
||||||
"Use `{}ww code` to pick a new game"
|
"Currently **{} / {}**\n"
|
||||||
"".format(len(self.players), len(self.roles), ctx.prefix))
|
"Use `{}ww code` to pick a new game"
|
||||||
|
"".format(len(self.players), len(self.roles), ctx.prefix)
|
||||||
|
)
|
||||||
self.roles = []
|
self.roles = []
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.game_role is None:
|
if self.game_role is None:
|
||||||
try:
|
try:
|
||||||
self.game_role = await ctx.guild.create_role(name="WW Players",
|
self.game_role = await ctx.guild.create_role(
|
||||||
hoist=True,
|
name="WW Players",
|
||||||
mentionable=True,
|
hoist=True,
|
||||||
reason="(BOT) Werewolf game role")
|
mentionable=True,
|
||||||
|
reason="(BOT) Werewolf game role",
|
||||||
|
)
|
||||||
self.to_delete.add(self.game_role)
|
self.to_delete.add(self.game_role)
|
||||||
except (discord.Forbidden, discord.HTTPException):
|
except (discord.Forbidden, discord.HTTPException):
|
||||||
await ctx.maybe_send_embed("Game role not configured and unable to generate one, cannot start")
|
await ctx.maybe_send_embed(
|
||||||
|
"Game role not configured and unable to generate one, cannot start"
|
||||||
|
)
|
||||||
self.roles = []
|
self.roles = []
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
@ -120,24 +133,33 @@ class Game:
|
|||||||
await player.member.add_roles(*[self.game_role])
|
await player.member.add_roles(*[self.game_role])
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Unable to add role **{}**\nBot is missing `manage_roles` permissions".format(self.game_role.name))
|
"Unable to add role **{}**\nBot is missing `manage_roles` permissions".format(
|
||||||
|
self.game_role.name
|
||||||
|
)
|
||||||
|
)
|
||||||
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=True, send_messages=False,
|
self.guild.default_role: discord.PermissionOverwrite(
|
||||||
add_reactions=False),
|
read_messages=True, send_messages=False, add_reactions=False
|
||||||
self.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True, add_reactions=True,
|
),
|
||||||
manage_messages=True, manage_channels=True,
|
self.guild.me: discord.PermissionOverwrite(
|
||||||
manage_roles=True),
|
read_messages=True,
|
||||||
self.game_role: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
send_messages=True,
|
||||||
|
add_reactions=True,
|
||||||
|
manage_messages=True,
|
||||||
|
manage_channels=True,
|
||||||
|
manage_roles=True,
|
||||||
|
),
|
||||||
|
self.game_role: discord.PermissionOverwrite(read_messages=True, send_messages=True),
|
||||||
}
|
}
|
||||||
if self.channel_category is None:
|
if self.channel_category is None:
|
||||||
self.channel_category = await self.guild.create_category("Werewolf Game",
|
self.channel_category = await self.guild.create_category(
|
||||||
overwrites=overwrite,
|
"Werewolf Game", overwrites=overwrite, reason="(BOT) New game of werewolf"
|
||||||
reason="(BOT) New game of werewolf")
|
)
|
||||||
else: # No need to modify categories
|
else: # No need to modify categories
|
||||||
pass
|
pass
|
||||||
# await self.channel_category.edit(name="🔴 Werewolf Game (ACTIVE)", reason="(BOT) New game of werewolf")
|
# await self.channel_category.edit(name="🔴 Werewolf Game (ACTIVE)", reason="(BOT) New game of werewolf")
|
||||||
@ -147,20 +169,26 @@ class Game:
|
|||||||
# reason="(BOT) New game of werewolf")
|
# reason="(BOT) New game of werewolf")
|
||||||
if self.village_channel is None:
|
if self.village_channel is None:
|
||||||
try:
|
try:
|
||||||
self.village_channel = await self.guild.create_text_channel("🔵Werewolf",
|
self.village_channel = await self.guild.create_text_channel(
|
||||||
overwrites=overwrite,
|
"🔵Werewolf",
|
||||||
reason="(BOT) New game of werewolf",
|
overwrites=overwrite,
|
||||||
category=self.channel_category)
|
reason="(BOT) New game of werewolf",
|
||||||
|
category=self.channel_category,
|
||||||
|
)
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
await ctx.send("Unable to create Game Channel and none was provided\n"
|
await ctx.send(
|
||||||
"Grant Bot appropriate permissions or assign a game_channel")
|
"Unable to create Game Channel and none was provided\n"
|
||||||
|
"Grant Bot appropriate permissions or assign a game_channel"
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.save_perms[self.village_channel] = self.village_channel.overwrites
|
self.save_perms[self.village_channel] = self.village_channel.overwrites
|
||||||
try:
|
try:
|
||||||
await self.village_channel.edit(name="🔵Werewolf",
|
await self.village_channel.edit(
|
||||||
category=self.channel_category,
|
name="🔵Werewolf",
|
||||||
reason="(BOT) New game of werewolf")
|
category=self.channel_category,
|
||||||
|
reason="(BOT) New game of werewolf",
|
||||||
|
)
|
||||||
except discord.Forbidden as e:
|
except discord.Forbidden as e:
|
||||||
print("Unable to rename Game Channel")
|
print("Unable to rename Game Channel")
|
||||||
print(e)
|
print(e)
|
||||||
@ -170,12 +198,14 @@ class Game:
|
|||||||
for target, ow in overwrite.items():
|
for target, ow in overwrite.items():
|
||||||
curr = self.village_channel.overwrites_for(target)
|
curr = self.village_channel.overwrites_for(target)
|
||||||
curr.update(**{perm: value for perm, value in ow})
|
curr.update(**{perm: value for perm, value in ow})
|
||||||
await self.village_channel.set_permissions(target=target,
|
await self.village_channel.set_permissions(
|
||||||
overwrite=curr,
|
target=target, overwrite=curr, reason="(BOT) New game of werewolf"
|
||||||
reason="(BOT) New game of werewolf")
|
)
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
await ctx.send("Unable to edit Game Channel permissions\n"
|
await ctx.send(
|
||||||
"Grant Bot appropriate permissions to manage permissions")
|
"Unable to edit Game Channel permissions\n"
|
||||||
|
"Grant Bot appropriate permissions to manage permissions"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
self.started = True
|
self.started = True
|
||||||
# Assuming everything worked so far
|
# Assuming everything worked so far
|
||||||
@ -186,18 +216,25 @@ class Game:
|
|||||||
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, send_messages=True, add_reactions=True,
|
self.guild.me: discord.PermissionOverwrite(
|
||||||
manage_messages=True, manage_channels=True,
|
read_messages=True,
|
||||||
manage_roles=True)
|
send_messages=True,
|
||||||
|
add_reactions=True,
|
||||||
|
manage_messages=True,
|
||||||
|
manage_channels=True,
|
||||||
|
manage_roles=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(
|
||||||
overwrites=overwrite,
|
channel_id,
|
||||||
reason="(BOT) WW game secret channel",
|
overwrites=overwrite,
|
||||||
category=self.channel_category)
|
reason="(BOT) WW game secret channel",
|
||||||
|
category=self.channel_category,
|
||||||
|
)
|
||||||
|
|
||||||
self.p_channels[channel_id]["channel"] = channel
|
self.p_channels[channel_id]["channel"] = channel
|
||||||
|
|
||||||
@ -216,8 +253,8 @@ class Game:
|
|||||||
async def _cycle(self):
|
async def _cycle(self):
|
||||||
"""
|
"""
|
||||||
Each event calls the next event
|
Each event calls the next event
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_at_day_start()
|
_at_day_start()
|
||||||
_at_voted()
|
_at_voted()
|
||||||
@ -225,7 +262,7 @@ class Game:
|
|||||||
_at_day_end()
|
_at_day_end()
|
||||||
_at_night_begin()
|
_at_night_begin()
|
||||||
_at_night_end()
|
_at_night_end()
|
||||||
|
|
||||||
and repeat with _at_day_start() again
|
and repeat with _at_day_start() again
|
||||||
"""
|
"""
|
||||||
await self._at_day_start()
|
await self._at_day_start()
|
||||||
@ -237,7 +274,8 @@ class Game:
|
|||||||
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)
|
||||||
|
|
||||||
@ -271,7 +309,9 @@ class Game:
|
|||||||
await asyncio.sleep(24) # 4 minute days FixMe to 120 later
|
await asyncio.sleep(24) # 4 minute days FixMe to 120 later
|
||||||
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(24) # 4 minute days FixMe to 120 later
|
await asyncio.sleep(24) # 4 minute days FixMe to 120 later
|
||||||
|
|
||||||
# Need a loop here to wait for trial to end (can_vote?)
|
# Need a loop here to wait for trial to end (can_vote?)
|
||||||
@ -295,7 +335,10 @@ class Game:
|
|||||||
|
|
||||||
await self.speech_perms(self.village_channel, target.member) # Only target can talk
|
await self.speech_perms(self.village_channel, target.member) # Only target can talk
|
||||||
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)
|
||||||
|
|
||||||
@ -305,7 +348,8 @@ class Game:
|
|||||||
"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 message.add_reaction("👍")
|
await message.add_reaction("👍")
|
||||||
await message.add_reaction("👎")
|
await message.add_reaction("👎")
|
||||||
@ -317,9 +361,9 @@ class Game:
|
|||||||
down_votes = sum(p for p in reaction_list if p.emoji == "👎" and not p.me)
|
down_votes = sum(p for p in reaction_list if p.emoji == "👎" and not p.me)
|
||||||
|
|
||||||
if down_votes > up_votes:
|
if down_votes > 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(up_votes), inline=True)
|
embed.add_field(name="👎", value="**{}**".format(up_votes), inline=True)
|
||||||
embed.add_field(name="👍", value="**{}**".format(down_votes), inline=True)
|
embed.add_field(name="👍", value="**{}**".format(down_votes), inline=True)
|
||||||
@ -339,7 +383,8 @@ class Game:
|
|||||||
else:
|
else:
|
||||||
await self.village_channel.send(
|
await self.village_channel.send(
|
||||||
"**{}**/**{}** of today's votes have been used!\n"
|
"**{}**/**{}** of today's votes have been used!\n"
|
||||||
"Nominate carefully..".format(self.used_votes, self.day_vote_count))
|
"Nominate carefully..".format(self.used_votes, self.day_vote_count)
|
||||||
|
)
|
||||||
|
|
||||||
self.ongoing_vote = False
|
self.ongoing_vote = False
|
||||||
|
|
||||||
@ -373,7 +418,9 @@ class Game:
|
|||||||
|
|
||||||
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)
|
||||||
@ -385,9 +432,13 @@ class Game:
|
|||||||
await self._notify(6)
|
await self._notify(6)
|
||||||
|
|
||||||
await asyncio.sleep(12) # 2 minutes FixMe to 120 later
|
await asyncio.sleep(12) # 2 minutes FixMe to 120 later
|
||||||
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(9) # 1.5 minutes FixMe to 90 later
|
await asyncio.sleep(9) # 1.5 minutes FixMe to 90 later
|
||||||
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(3) # .5 minutes FixMe to 3 Later
|
await asyncio.sleep(3) # .5 minutes FixMe to 3 Later
|
||||||
|
|
||||||
await self._at_night_end()
|
await self._at_night_end()
|
||||||
@ -413,10 +464,12 @@ class Game:
|
|||||||
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
|
||||||
@ -432,13 +485,17 @@ class Game:
|
|||||||
else:
|
else:
|
||||||
status = "*[Dead]*-"
|
status = "*[Dead]*-"
|
||||||
if with_roles or not player.alive:
|
if with_roles or not player.alive:
|
||||||
embed.add_field(name="ID# **{}**".format(i),
|
embed.add_field(
|
||||||
value="{}{}-{}".format(status, player.member.display_name, str(player.role)),
|
name="ID# **{}**".format(i),
|
||||||
inline=True)
|
value="{}{}-{}".format(status, player.member.display_name, str(player.role)),
|
||||||
|
inline=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
embed.add_field(name="ID# **{}**".format(i),
|
embed.add_field(
|
||||||
value="{}{}".format(status, player.member.display_name),
|
name="ID# **{}**".format(i),
|
||||||
inline=True)
|
value="{}{}".format(status, player.member.display_name),
|
||||||
|
inline=True,
|
||||||
|
)
|
||||||
|
|
||||||
return await channel.send(embed=embed)
|
return await channel.send(embed=embed)
|
||||||
|
|
||||||
@ -479,10 +536,15 @@ class Game:
|
|||||||
await member.add_roles(*[self.game_role])
|
await member.add_roles(*[self.game_role])
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
await channel.send(
|
await channel.send(
|
||||||
"Unable to add role **{}**\nBot is missing `manage_roles` permissions".format(self.game_role.name))
|
"Unable to add role **{}**\nBot is missing `manage_roles` permissions".format(
|
||||||
|
self.game_role.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
await channel.send("{} has been added to the game, "
|
await channel.send(
|
||||||
"total players is **{}**".format(member.mention, len(self.players)))
|
"{} has been added to the game, "
|
||||||
|
"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):
|
||||||
"""
|
"""
|
||||||
@ -499,7 +561,11 @@ 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 member.remove_roles(*[self.game_role])
|
await member.remove_roles(*[self.game_role])
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
@ -598,14 +664,20 @@ class Game:
|
|||||||
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. "
|
""
|
||||||
"{} more votes needed".format(author.mention,
|
"{} has voted to put {} to trial. "
|
||||||
target.member.mention,
|
"{} more votes needed".format(
|
||||||
required_votes - self.vote_totals[target_id]))
|
author.mention,
|
||||||
|
target.member.mention,
|
||||||
|
required_votes - self.vote_totals[target_id],
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.vote_totals[target_id] = 0
|
self.vote_totals[target_id] = 0
|
||||||
self.day_vote = {k: v for k, v in self.day_vote.items() if v != target_id} # Remove votes for this id
|
self.day_vote = {
|
||||||
|
k: v for k, v in self.day_vote.items() if v != target_id
|
||||||
|
} # Remove votes for this id
|
||||||
await self._at_voted(target)
|
await self._at_voted(target)
|
||||||
|
|
||||||
async def eval_results(self, target, source=None, method=None):
|
async def eval_results(self, target, source=None, method=None):
|
||||||
@ -613,9 +685,9 @@ class Game:
|
|||||||
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} the {role} was found dead".format(ID=target.id,
|
return "**{ID}** - {target} the {role} was found dead".format(
|
||||||
target=target.member.display_name,
|
ID=target.id, target=target.member.display_name, role=await target.role.get_role()
|
||||||
role=await target.role.get_role())
|
)
|
||||||
|
|
||||||
async def _quit(self, player):
|
async def _quit(self, player):
|
||||||
"""
|
"""
|
||||||
@ -748,7 +820,9 @@ class Game:
|
|||||||
alive_players = [player for player in self.players if player.alive]
|
alive_players = [player for player in self.players if player.alive]
|
||||||
|
|
||||||
if len(alive_players) <= 0:
|
if len(alive_players) <= 0:
|
||||||
await self.village_channel.send(embed=discord.Embed(title="**Everyone is dead! Game Over!**"))
|
await self.village_channel.send(
|
||||||
|
embed=discord.Embed(title="**Everyone is dead! Game Over!**")
|
||||||
|
)
|
||||||
self.game_over = True
|
self.game_over = True
|
||||||
elif len(alive_players) == 1:
|
elif len(alive_players) == 1:
|
||||||
self.game_over = True
|
self.game_over = True
|
||||||
@ -780,17 +854,19 @@ class Game:
|
|||||||
|
|
||||||
async def _announce_winners(self, winnerlist):
|
async def _announce_winners(self, winnerlist):
|
||||||
await self.village_channel.send(self.game_role.mention)
|
await self.village_channel.send(self.game_role.mention)
|
||||||
embed = discord.Embed(title='Game Over', description='The Following Players have won!')
|
embed = discord.Embed(title="Game Over", description="The Following Players have won!")
|
||||||
for player in winnerlist:
|
for player in winnerlist:
|
||||||
embed.add_field(name=player.member.display_name, value=str(player.role), inline=True)
|
embed.add_field(name=player.member.display_name, value=str(player.role), inline=True)
|
||||||
embed.set_thumbnail(url='https://emojipedia-us.s3.amazonaws.com/thumbs/160/twitter/134/trophy_1f3c6.png')
|
embed.set_thumbnail(
|
||||||
|
url="https://emojipedia-us.s3.amazonaws.com/thumbs/160/twitter/134/trophy_1f3c6.png"
|
||||||
|
)
|
||||||
await self.village_channel.send(embed=embed)
|
await self.village_channel.send(embed=embed)
|
||||||
|
|
||||||
await self.generate_targets(self.village_channel, True)
|
await self.generate_targets(self.village_channel, True)
|
||||||
|
|
||||||
async def _end_game(self):
|
async def _end_game(self):
|
||||||
# Remove game_role access for potential archiving for now
|
# Remove game_role access for potential archiving for now
|
||||||
reason = '(BOT) End of WW game'
|
reason = "(BOT) End of WW game"
|
||||||
for obj in self.to_delete:
|
for obj in self.to_delete:
|
||||||
print(obj)
|
print(obj)
|
||||||
await obj.delete(reason=reason)
|
await obj.delete(reason=reason)
|
||||||
@ -798,8 +874,12 @@ class Game:
|
|||||||
try:
|
try:
|
||||||
await self.village_channel.edit(reason=reason, name="Werewolf")
|
await self.village_channel.edit(reason=reason, name="Werewolf")
|
||||||
for target, overwrites in self.save_perms[self.village_channel]:
|
for target, overwrites in self.save_perms[self.village_channel]:
|
||||||
await self.village_channel.set_permissions(target, overwrite=overwrites, reason=reason)
|
await self.village_channel.set_permissions(
|
||||||
await self.village_channel.set_permissions(self.game_role, overwrite=None, reason=reason)
|
target, overwrite=overwrites, reason=reason
|
||||||
|
)
|
||||||
|
await self.village_channel.set_permissions(
|
||||||
|
self.game_role, overwrite=None, reason=reason
|
||||||
|
)
|
||||||
except (discord.HTTPException, discord.NotFound, discord.errors.NotFound):
|
except (discord.HTTPException, discord.NotFound, discord.errors.NotFound):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
class Role:
|
class Role:
|
||||||
"""
|
"""
|
||||||
Base Role class for werewolf game
|
Base Role class for werewolf game
|
||||||
|
|
||||||
Category enrollment guide as follows (category property):
|
Category enrollment guide as follows (category property):
|
||||||
Town:
|
Town:
|
||||||
1: Random, 2: Investigative, 3: Protective, 4: Government,
|
1: Random, 2: Investigative, 3: Protective, 4: Government,
|
||||||
5: Killing, 6: Power (Special night action)
|
5: Killing, 6: Power (Special night action)
|
||||||
|
|
||||||
Werewolf:
|
Werewolf:
|
||||||
11: Random, 12: Deception, 15: Killing, 16: Support
|
11: Random, 12: Deception, 15: Killing, 16: Support
|
||||||
|
|
||||||
Neutral:
|
Neutral:
|
||||||
21: Benign, 22: Evil, 23: Killing
|
21: Benign, 22: Evil, 23: Killing
|
||||||
|
|
||||||
|
|
||||||
Example category:
|
Example category:
|
||||||
category = [1, 5, 6] Could be Veteran
|
category = [1, 5, 6] Could be Veteran
|
||||||
category = [1, 5] Could be Bodyguard
|
category = [1, 5] Could be Bodyguard
|
||||||
category = [11, 16] Could be Werewolf Silencer
|
category = [11, 16] Could be Werewolf Silencer
|
||||||
|
|
||||||
|
|
||||||
Action guide as follows (on_event function):
|
Action guide as follows (on_event function):
|
||||||
_at_night_start
|
_at_night_start
|
||||||
0. No Action
|
0. No Action
|
||||||
1. Detain actions (Jailer/Kidnapper)
|
1. Detain actions (Jailer/Kidnapper)
|
||||||
2. Group discussions and choose targets
|
2. Group discussions and choose targets
|
||||||
|
|
||||||
_at_night_end
|
_at_night_end
|
||||||
0. No Action
|
0. No Action
|
||||||
1. Self actions (Veteran)
|
1. Self actions (Veteran)
|
||||||
@ -68,7 +68,7 @@ class Role:
|
|||||||
(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),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -23,7 +23,7 @@ class VoteGroup:
|
|||||||
(self._at_day_end, 0),
|
(self._at_day_end, 0),
|
||||||
(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):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user