Adding constants

pull/147/head
bobloy 4 years ago
parent eb0c79ef1d
commit 61049c2343

@ -1,6 +1,7 @@
import bisect
import logging
from collections import defaultdict
from operator import attrgetter
from random import choice
import discord
@ -16,6 +17,7 @@ from redbot.core import commands
from werewolf import roles
from redbot.core.utils.menus import menu, prev_page, next_page, close_menu
from werewolf.constants import ROLE_CATEGORY_DESCRIPTIONS
from werewolf.role import Role
log = logging.getLogger("red.fox_v3.werewolf.builder")
@ -25,104 +27,40 @@ log = logging.getLogger("red.fox_v3.werewolf.builder")
ROLE_DICT = {name: cls for name, cls in roles.__dict__.items() if isinstance(cls, type)}
ROLE_LIST = sorted(
[cls for cls in ROLE_DICT.values()],
key=lambda x: x.alignment,
key=attrgetter('alignment'),
)
log.debug(f"{ROLE_DICT=}")
# Town, Werewolf, Neutral
ALIGNMENT_COLORS = [0x008000, 0xFF0000, 0xC0C0C0]
# TOWN_ROLES = [(idx, role) for idx, r_tuple in enumerate(ROLE_LIST) if role.alignment == 1]
# WW_ROLES = [(idx, role) for idx, r_tuple in enumerate(ROLE_LIST) if role.alignment == 2]
# OTHER_ROLES = [
# (idx, role) for idx, r_tuple in enumerate(ROLE_LIST) if role.alignment not in [0, 1]
# ]
ROLE_PAGES = []
PAGE_GROUPS = [0]
ROLE_CATEGORIES = {
1: "Random",
2: "Investigative",
3: "Protective",
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 = []
def role_embed(idx, role, color):
def role_embed(idx, role: Role, color):
embed = discord.Embed(
title=f"**{idx}** - {role.__name__}",
description=role.game_start_message,
color=color,
)
if role.icon_url is not None:
embed.set_thumbnail(url=role.icon_url)
embed.add_field(
name="Alignment", value=["Town", "Werewolf", "Neutral"][role.alignment - 1], inline=True
name="Alignment", value=["Town", "Werewolf", "Neutral"][role.alignment - 1], inline=False
)
embed.add_field(name="Multiples Allowed", value=str(not role.unique), inline=True)
embed.add_field(name="Multiples Allowed", value=str(not role.unique), inline=False)
embed.add_field(
name="Role Type", value=", ".join(ROLE_CATEGORIES[x] for x in role.category), inline=True
name="Role Types",
value=", ".join(ROLE_CATEGORY_DESCRIPTIONS[x] for x in role.category),
inline=False,
)
embed.add_field(name="Random Option", value=str(role.rand_choice), inline=True)
embed.add_field(name="Random Option", value=str(role.rand_choice), inline=False)
return embed
def setup():
# Roles
last_alignment = ROLE_LIST[0].alignment
for idx, role in enumerate(ROLE_LIST):
if role.alignment != last_alignment and len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
last_alignment = role.alignment
ROLE_PAGES.append(role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1]))
# Random Town Roles
if len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORIES.items():
if 0 < k <= 6:
ROLE_PAGES.append(
discord.Embed(title="RANDOM:Town Role", description=f"Town {v}", color=0x008000)
)
CATEGORY_COUNT.append(k)
# Random WW Roles
if len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORIES.items():
if 10 < k <= 16:
ROLE_PAGES.append(
discord.Embed(
title="RANDOM:Werewolf Role",
description=f"Werewolf {v}",
color=0xFF0000,
)
)
CATEGORY_COUNT.append(k)
# Random Neutral Roles
if len(ROLE_PAGES) - 1 not in PAGE_GROUPS:
PAGE_GROUPS.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORIES.items():
if 20 < k <= 26:
ROLE_PAGES.append(
discord.Embed(
title=f"RANDOM:Neutral Role", description="Neutral {v}", color=0xC0C0C0
)
)
CATEGORY_COUNT.append(k)
"""
Example code:
0 = Villager
@ -189,15 +127,15 @@ async def parse_code(code, game):
return decode
async def encode(roles, rand_roles):
async def encode(role_list, rand_roles):
"""Convert role list to code"""
out_code = ""
digit_sort = sorted(role for role in roles if role < 10)
digit_sort = sorted(role for role in role_list if role < 10)
for role in digit_sort:
out_code += str(role)
digit_sort = sorted(role for role in roles if 10 <= role < 100)
digit_sort = sorted(role for role in role_list if 10 <= role < 100)
if digit_sort:
out_code += "-"
for role in digit_sort:
@ -229,51 +167,6 @@ async def encode(roles, rand_roles):
return out_code
async def next_group(
ctx: commands.Context,
pages: list,
controls: dict,
message: discord.Message,
page: int,
timeout: float,
emoji: str,
):
perms = message.channel.permissions_for(ctx.me)
if perms.manage_messages: # Can manage messages, so remove react
try:
await message.remove_reaction(emoji, ctx.author)
except discord.NotFound:
pass
page = bisect.bisect_right(PAGE_GROUPS, page)
if page == len(PAGE_GROUPS):
page = PAGE_GROUPS[0]
else:
page = PAGE_GROUPS[page]
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
async def prev_group(
ctx: commands.Context,
pages: list,
controls: dict,
message: discord.Message,
page: int,
timeout: float,
emoji: str,
):
perms = message.channel.permissions_for(ctx.me)
if perms.manage_messages: # Can manage messages, so remove react
try:
await message.remove_reaction(emoji, ctx.author)
except discord.NotFound:
pass
page = PAGE_GROUPS[bisect.bisect_left(PAGE_GROUPS, page) - 1]
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
def role_from_alignment(alignment):
return [
role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1])
@ -316,11 +209,11 @@ def say_role_list(code_list, rand_roles):
for role in rand_roles:
if 0 < role <= 6:
role_dict[f"Town {ROLE_CATEGORIES[role]}"] += 1
role_dict[f"Town {ROLE_CATEGORY_DESCRIPTIONS[role]}"] += 1
if 10 < role <= 16:
role_dict[f"Werewolf {ROLE_CATEGORIES[role]}"] += 1
role_dict[f"Werewolf {ROLE_CATEGORY_DESCRIPTIONS[role]}"] += 1
if 20 < role <= 26:
role_dict[f"Neutral {ROLE_CATEGORIES[role]}"] += 1
role_dict[f"Neutral {ROLE_CATEGORY_DESCRIPTIONS[role]}"] += 1
for k, v in role_dict.items():
embed.add_field(name=k, value=f"Count: {v}", inline=True)
@ -332,15 +225,69 @@ class GameBuilder:
def __init__(self):
self.code = []
self.rand_roles = []
setup()
self.page_groups = [0]
self.category_count = []
self.setup()
def setup(self):
# Roles
last_alignment = ROLE_LIST[0].alignment
for idx, role in enumerate(ROLE_LIST):
if role.alignment != last_alignment and len(ROLE_PAGES) - 1 not in self.page_groups:
self.page_groups.append(len(ROLE_PAGES) - 1)
last_alignment = role.alignment
ROLE_PAGES.append(role_embed(idx, role, ALIGNMENT_COLORS[role.alignment - 1]))
# Random Town Roles
if len(ROLE_PAGES) - 1 not in self.page_groups:
self.page_groups.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORY_DESCRIPTIONS.items():
if 0 < k <= 9:
ROLE_PAGES.append(
discord.Embed(
title="RANDOM:Town Role",
description=f"Town {v}",
color=ALIGNMENT_COLORS[0],
)
)
self.category_count.append(k)
# Random WW Roles
if len(ROLE_PAGES) - 1 not in self.page_groups:
self.page_groups.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORY_DESCRIPTIONS.items():
if 10 < k <= 19:
ROLE_PAGES.append(
discord.Embed(
title="RANDOM:Werewolf Role",
description=f"Werewolf {v}",
color=ALIGNMENT_COLORS[1],
)
)
self.category_count.append(k)
# Random Neutral Roles
if len(ROLE_PAGES) - 1 not in self.page_groups:
self.page_groups.append(len(ROLE_PAGES) - 1)
for k, v in ROLE_CATEGORY_DESCRIPTIONS.items():
if 20 < k <= 29:
ROLE_PAGES.append(
discord.Embed(
title=f"RANDOM:Neutral Role",
description=f"Neutral {v}",
color=ALIGNMENT_COLORS[2],
)
)
self.category_count.append(k)
async def build_game(self, ctx: commands.Context):
new_controls = {
"": prev_group,
"": self.prev_group,
"": prev_page,
"": self.select_page,
"": next_page,
"": next_group,
"": self.next_group,
"📇": self.list_roles,
"": close_menu,
}
@ -391,8 +338,53 @@ class GameBuilder:
pass
if page >= len(ROLE_LIST):
self.rand_roles.append(CATEGORY_COUNT[page - len(ROLE_LIST)])
self.rand_roles.append(self.category_count[page - len(ROLE_LIST)])
else:
self.code.append(page)
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
async def next_group(
self,
ctx: commands.Context,
pages: list,
controls: dict,
message: discord.Message,
page: int,
timeout: float,
emoji: str,
):
perms = message.channel.permissions_for(ctx.me)
if perms.manage_messages: # Can manage messages, so remove react
try:
await message.remove_reaction(emoji, ctx.author)
except discord.NotFound:
pass
page = bisect.bisect_right(self.page_groups, page)
if page == len(self.page_groups):
page = self.page_groups[0]
else:
page = self.page_groups[page]
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)
async def prev_group(
self,
ctx: commands.Context,
pages: list,
controls: dict,
message: discord.Message,
page: int,
timeout: float,
emoji: str,
):
perms = message.channel.permissions_for(ctx.me)
if perms.manage_messages: # Can manage messages, so remove react
try:
await message.remove_reaction(emoji, ctx.author)
except discord.NotFound:
pass
page = self.page_groups[bisect.bisect_left(self.page_groups, page) - 1]
return await menu(ctx, pages, controls, message=message, page=page, timeout=timeout)

@ -0,0 +1,91 @@
"""
Role Constants
Role Alignment guide as follows:
Town: 1
Werewolf: 2
Neutral: 3
Additional alignments may be added when warring factions are added
(Rival werewolves, cultists, vampires)
Role Category enrollment guide as follows (See Role.category):
Town:
1: Random, 2: Investigative, 3: Protective, 4: Government,
5: Killing, 6: Power (Special night action)
Werewolf:
11: Random, 12: Deception, 15: Killing, 16: Support
Neutral:
21: Benign, 22: Evil, 23: Killing
Example category:
category = [1, 5, 6] Could be Veteran
category = [1, 5] Could be Bodyguard
category = [11, 16] Could be Werewolf Silencer
category = [22] Could be Blob (non-killing)
category = [22, 23] Could be Serial-Killer
"""
ALIGNMENT_TOWN = 1
ALIGNMENT_WEREWOLF = 2
ALIGNMENT_NEUTRAL = 3
ALIGNMENT_MAP = {"Town": 1, "Werewolf": 2, "Neutral": 3}
# 0-9: Town Role Categories
# 10-19: Werewolf Role Categories
# 20-29: Neutral Role Categories
CATEGORY_TOWN_RANDOM = 1
CATEGORY_TOWN_INVESTIGATIVE = 2
CATEGORY_TOWN_PROTECTIVE = 3
CATEGORY_TOWN_GOVERNMENT = 4
CATEGORY_TOWN_KILLING = 5
CATEGORY_TOWN_POWER = 6
CATEGORY_WW_RANDOM = 11
CATEGORY_WW_DECEPTION = 12
CATEGORY_WW_KILLING = 15
CATEGORY_WW_SUPPORT = 16
CATEGORY_NEUTRAL_BENIGN = 21
CATEGORY_NEUTRAL_EVIL = 22
CATEGORY_NEUTRAL_KILLING = 23
ROLE_CATEGORY_DESCRIPTIONS = {
CATEGORY_TOWN_RANDOM: "Random",
CATEGORY_TOWN_INVESTIGATIVE: "Investigative",
CATEGORY_TOWN_PROTECTIVE: "Protective",
CATEGORY_TOWN_GOVERNMENT: "Government",
CATEGORY_TOWN_KILLING: "Killing",
CATEGORY_TOWN_POWER: "Power (Special night action)",
CATEGORY_WW_RANDOM: "Random",
CATEGORY_WW_DECEPTION: "Deception",
CATEGORY_WW_KILLING: "Killing",
CATEGORY_WW_SUPPORT: "Support",
CATEGORY_NEUTRAL_BENIGN: "Benign",
CATEGORY_NEUTRAL_EVIL: "Evil",
CATEGORY_NEUTRAL_KILLING: "Killing",
}
"""
Listener Actions Priority Guide
Action priority guide as follows (see listeners.py for wolflistener):
_at_night_start
0. No Action
1. Detain actions (Jailer/Kidnapper)
2. Group discussions and choose targets
_at_night_end
0. No Action
1. Self actions (Veteran)
2. Target switching and role blocks (bus driver, witch, escort)
3. Protection / Preempt actions (bodyguard/framer)
4. Non-disruptive actions (seer/silencer)
5. Disruptive actions (Killing)
6. Role altering actions (Cult / Mason / Shifter)
"""

@ -639,14 +639,14 @@ class Game:
await target.role.visit(source)
await self._at_visit(target, source)
async def visit(self, target_id, source):
async def visit(self, target_id, source) -> Union[Player, None]:
"""
Night visit target_id
Returns a target for role information (i.e. Seer)
"""
if source.role.blocked:
# Blocker handles text
return
return None
target = await self.get_night_target(target_id, source)
await self._visit(target, source)
return target
@ -786,10 +786,10 @@ class Game:
if not target.alive: # Still dead after notifying
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) -> Player:
return self.players[target_id] # ToDo check source
async def get_day_target(self, target_id, source=None):
async def get_day_target(self, target_id, source=None) -> Player:
return self.players[target_id] # ToDo check source
async def set_code(self, ctx: commands.Context, game_code):
@ -829,7 +829,7 @@ class Game:
# Sorted players, now assign id's
await self.players[idx].assign_id(idx)
async def get_player_by_member(self, member):
async def get_player_by_member(self, member: discord.Member):
for player in self.players:
if player.member == member:
return player

@ -26,6 +26,8 @@ class Role(WolfListener):
category = [1, 5, 6] Could be Veteran
category = [1, 5] Could be Bodyguard
category = [11, 16] Could be Werewolf Silencer
category = [22] Could be Blob (non-killing)
category = [22, 23] Could be Serial-Killer
Action priority guide as follows (on_event function):
@ -44,10 +46,12 @@ class Role(WolfListener):
6. Role altering actions (Cult / Mason / Shifter)
"""
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
# Determines if it can be picked as a random role (False for unusually disruptive roles)
rand_choice = False # TODO: Rework random with categories
town_balance = 0 # Guess at power level and it's balance on the town
category = [0] # List of enrolled categories (listed above)
alignment = 0 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel
channel_name = "" # Empty for no private channel
unique = False # Only one of this role per game
game_start_message = (
"Your role is **Default**\n"
@ -68,28 +72,9 @@ class Role(WolfListener):
self.blocked = False
self.properties = {} # Extra data for other roles (i.e. arsonist)
# self.action_list = [
# (self._at_game_start, 1), # (Action, Priority)
# (self._at_day_start, 0),
# (self._at_voted, 0),
# (self._at_kill, 0),
# (self._at_hang, 0),
# (self._at_day_end, 0),
# (self._at_night_start, 0),
# (self._at_night_end, 0),
# (self._at_visit, 0),
# ]
def __repr__(self):
return self.__class__.__name__
# async def on_event(self, event, data):
# """
# See Game class for event guide
# """
#
# await self.action_list[event][0](data)
async def assign_player(self, player):
"""
Give this role a player
@ -110,7 +95,7 @@ class Role(WolfListener):
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting
to see alignment (Village, Werewolf Other)
to see alignment (Village, Werewolf, Other)
"""
return "Other"
@ -128,37 +113,13 @@ class Role(WolfListener):
"""
return "Default"
@wolflistener("at_game_start", priority=1)
@wolflistener("at_game_start", priority=2)
async def _at_game_start(self):
if self.channel_id:
await self.game.register_channel(self.channel_id, self)
if self.channel_name:
await self.game.register_channel(self.channel_name, self)
await self.player.send_dm(self.game_start_message) # Maybe embeds eventually
# async def _at_day_start(self, data=None):
# pass
#
# async def _at_voted(self, data=None):
# pass
#
# async def _at_kill(self, data=None):
# pass
#
# async def _at_hang(self, data=None):
# pass
#
# async def _at_day_end(self, data=None):
# pass
#
# async def _at_night_start(self, data=None):
# pass
#
# async def _at_night_end(self, data=None):
# pass
#
# async def _at_visit(self, data=None):
# pass
async def kill(self, source):
"""
Called when someone is trying to kill you!

@ -1,5 +1,7 @@
import logging
from werewolf.constants import ALIGNMENT_TOWN, ALIGNMENT_WEREWOLF, CATEGORY_TOWN_INVESTIGATIVE, \
CATEGORY_TOWN_RANDOM
from werewolf.listener import wolflistener
from werewolf.night_powers import pick_target
from werewolf.role import Role
@ -8,9 +10,12 @@ log = logging.getLogger("red.fox_v3.werewolf.role.seer")
class Seer(Role):
rand_choice = True # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [1, 2] # List of enrolled categories (listed above)
alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
rand_choice = True
category = [
CATEGORY_TOWN_RANDOM,
CATEGORY_TOWN_INVESTIGATIVE,
] # List of enrolled categories (listed above)
alignment = ALIGNMENT_TOWN # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game
game_start_message = (
@ -46,23 +51,23 @@ class Seer(Role):
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting
to see team (Village, Werewolf Other)
to see team (Village, Werewolf, Other)
"""
return "Village"
return ALIGNMENT_TOWN
async def get_role(self, source=None):
"""
Interaction for powerful access of role
Unlikely to be able to deceive this
"""
return "Villager"
return "Seer"
async def see_role(self, source=None):
"""
Interaction for investigative roles.
More common to be able to deceive these roles
"""
return "Villager"
return "Seer"
@wolflistener("at_night_start", priority=2)
async def _at_night_start(self):
@ -84,9 +89,9 @@ class Seer(Role):
if target:
alignment = await target.role.see_alignment(self.player)
if alignment == "Werewolf":
if alignment == ALIGNMENT_WEREWOLF:
out = "Your insight reveals this player to be a **Werewolf!**"
else:
else: # Don't reveal neutrals
out = "You fail to find anything suspicious about this player..."
await self.player.send_dm(out)

@ -1,5 +1,6 @@
import logging
from werewolf.constants import ALIGNMENT_NEUTRAL, CATEGORY_NEUTRAL_BENIGN
from werewolf.listener import wolflistener
from werewolf.night_powers import pick_target
from werewolf.role import Role
@ -46,8 +47,9 @@ class Shifter(Role):
"""
rand_choice = False # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [22] # List of enrolled categories (listed above)
alignment = 3 # 1: Town, 2: Werewolf, 3: Neutral
town_balance = -3
category = [CATEGORY_NEUTRAL_BENIGN] # List of enrolled categories (listed above)
alignment = ALIGNMENT_NEUTRAL # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game
game_start_message = (
@ -81,7 +83,7 @@ class Shifter(Role):
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting
to see alignment (Village, Werewolf, Other)
to see alignment (Village, Werewolf,, Other)
"""
return "Other"

@ -1,5 +1,6 @@
import logging
from werewolf.constants import ALIGNMENT_WEREWOLF, CATEGORY_WW_KILLING, CATEGORY_WW_RANDOM
from werewolf.listener import wolflistener
from werewolf.role import Role
from werewolf.votegroups.wolfvote import WolfVote
@ -9,9 +10,10 @@ log = logging.getLogger("red.fox_v3.werewolf.role.vanillawerewolf")
class VanillaWerewolf(Role):
rand_choice = True
category = [11, 15]
alignment = 2 # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "werewolves"
town_balance = -6
category = [CATEGORY_WW_RANDOM, CATEGORY_WW_KILLING]
alignment = ALIGNMENT_WEREWOLF # 1: Town, 2: Werewolf, 3: Neutral
channel_name = "werewolves"
unique = False
game_start_message = (
"Your role is **Werewolf**\n"
@ -40,14 +42,14 @@ class VanillaWerewolf(Role):
Interaction for investigative roles attempting
to see team (Village, Werewolf Other)
"""
return "Werewolf"
return ALIGNMENT_WEREWOLF
async def get_role(self, source=None):
"""
Interaction for powerful access of role
Unlikely to be able to deceive this
"""
return "Werewolf"
return "VanillaWerewolf"
async def see_role(self, source=None):
"""
@ -56,12 +58,12 @@ class VanillaWerewolf(Role):
"""
return "Werewolf"
@wolflistener("at_game_start", priority=1)
@wolflistener("at_game_start", priority=2)
async def _at_game_start(self):
if self.channel_id:
log.debug("Wolf has channel_id: " + self.channel_id)
if self.channel_name:
log.debug("Wolf has channel_name: " + self.channel_name)
await self.game.register_channel(
self.channel_id, self, WolfVote
self.channel_name, self, WolfVote
) # Add VoteGroup WolfVote
await self.player.send_dm(self.game_start_message)

@ -1,14 +1,20 @@
import logging
from werewolf.constants import ALIGNMENT_TOWN, CATEGORY_TOWN_RANDOM
from werewolf.role import Role
log = logging.getLogger("red.fox_v3.werewolf.role.villager")
class Villager(Role):
rand_choice = True # Determines if it can be picked as a random role (False for unusually disruptive roles)
category = [1] # List of enrolled categories (listed above)
alignment = 1 # 1: Town, 2: Werewolf, 3: Neutral
# Determines if it can be picked as a random role (False for unusually disruptive roles)
rand_choice = True
town_balance = 1
category = [CATEGORY_TOWN_RANDOM] # List of enrolled categories (listed above)
alignment = ALIGNMENT_TOWN # 1: Town, 2: Werewolf, 3: Neutral
channel_id = "" # Empty for no private channel
unique = False # Only one of this role per game
game_start_message = (
@ -23,9 +29,9 @@ class Villager(Role):
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting
to see team (Village, Werewolf Other)
to see team (Village, Werewolf, Other)
"""
return "Village"
return ALIGNMENT_TOWN
async def get_role(self, source=None):
"""

@ -33,7 +33,7 @@ class Werewolf(Cog):
default_guild = {
"role_id": None,
"category_id": None,
"channel_id": None,
"channel_name": None,
"log_channel_id": None,
}

Loading…
Cancel
Save