More WIP progress

pull/147/head
bobloy 4 years ago
parent 8a42b87bd6
commit 3a6d3df374

@ -19,6 +19,14 @@ log = logging.getLogger("red.fox_v3.werewolf.game")
HALF_DAY_LENGTH = 24 # FixMe: to 120 later for 4 minute days
async def anyone_has_role(
member_list: List[discord.Member], role: discord.Role
) -> Union[None, discord.Member]:
return await AsyncIter(member_list).find(
lambda m: AsyncIter(m.roles).find(lambda r: r.id == role.id)
)
class Game:
"""
Base class to run a single game of Werewolf
@ -129,6 +137,7 @@ class Game:
self.roles = []
return False
# If there's no game role, make the role and delete it later in `self.to_delete`
if self.game_role is None:
try:
self.game_role = await ctx.guild.create_role(
@ -144,14 +153,25 @@ class Game:
)
self.roles = []
return False
try:
for player in self.players:
await player.member.add_roles(*[self.game_role])
except discord.Forbidden:
await ctx.send(
f"Unable to add role **{self.game_role.name}**\nBot is missing `manage_roles` permissions"
)
return False
anyone_with_role = await anyone_has_role(self.guild.members, self.game_role)
if anyone_with_role is not None:
await ctx.maybe_send_embed(
f"{anyone_with_role.display_name} has the game role, "
f"can't continue until no one has the role"
)
return False
try:
for player in self.players:
await player.member.add_roles(*[self.game_role])
except discord.Forbidden:
log.exception(f"Unable to add role **{self.game_role.name}**")
await ctx.send(
f"Unable to add role **{self.game_role.name}**\n"
f"Bot is missing `manage_roles` permissions"
)
return False
await self.assign_roles()
@ -223,9 +243,10 @@ class Game:
self.started = True
# Assuming everything worked so far
log.debug("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 add votegroups to self.p_channels
log.debug("Post at_game_start")
for channel_id in self.p_channels:
log.debug(f"Private channels: {self.p_channels}")
for channel_id in self.p_channels.keys():
log.debug("Setup Channel id: " + channel_id)
overwrite = {
self.guild.default_role: discord.PermissionOverwrite(read_messages=False),
@ -251,6 +272,8 @@ class Game:
self.p_channels[channel_id]["channel"] = channel
self.to_delete.add(channel)
if self.p_channels[channel_id]["votegroup"] is not None:
vote_group = self.p_channels[channel_id]["votegroup"](self, channel)
@ -259,8 +282,10 @@ class Game:
self.vote_groups[channel_id] = vote_group
log.debug("Pre-cycle")
await asyncio.sleep(1)
await asyncio.ensure_future(self._cycle()) # Start the loop
await asyncio.sleep(0)
asyncio.create_task(self._cycle()) # Start the loop
return True
# ###########START Notify structure############
async def _cycle(self):
@ -553,13 +578,14 @@ class Game:
try:
await asyncio.sleep(1) # This will have multiple calls
self.p_channels[channel_id]["players"].append(role.player)
if votegroup is not None:
self.p_channels[channel_id]["votegroup"] = votegroup
except AttributeError:
continue
else:
break
if votegroup is not None:
self.p_channels[channel_id]["votegroup"] = votegroup
async def join(self, member: discord.Member, channel: discord.TextChannel):
"""
Have a member join a game
@ -574,14 +600,15 @@ class Game:
self.players.append(Player(member))
if self.game_role is not None:
try:
await member.add_roles(*[self.game_role])
except discord.Forbidden:
await channel.send(
f"Unable to add role **{self.game_role.name}**\n"
f"Bot is missing `manage_roles` permissions"
)
# Add the role during setup, not before
# if self.game_role is not None:
# try:
# await member.add_roles(*[self.game_role])
# except discord.Forbidden:
# await channel.send(
# f"Unable to add role **{self.game_role.name}**\n"
# f"Bot is missing `manage_roles` permissions"
# )
await channel.send(
f"{member.display_name} has been added to the game, "
@ -908,7 +935,7 @@ class Game:
# Remove game_role access for potential archiving for now
reason = "(BOT) End of WW game"
for obj in self.to_delete:
log.debug(f"End_game: Deleting object {obj}")
log.debug(f"End_game: Deleting object {obj.__repr__()}")
await obj.delete(reason=reason)
try:
@ -926,6 +953,17 @@ class Game:
except (discord.HTTPException, discord.NotFound, discord.errors.NotFound):
pass
for player in self.players:
try:
await player.member.remove_roles(*[self.game_role])
except discord.Forbidden:
log.exception(f"Unable to add remove **{self.game_role.name}**")
# await ctx.send(
# f"Unable to add role **{self.game_role.name}**\n"
# f"Bot is missing `manage_roles` permissions"
# )
pass
# Optional dynamic channels/categories
def add_ww_listener(self, func, priority=0, name=None):

@ -20,6 +20,9 @@ class Player:
self.muted = False
self.protected = False
def __repr__(self):
return f"{self.__class__.__name__}({self.member})"
async def assign_role(self, role):
"""
Give this player a role

@ -73,7 +73,7 @@ class Role(WolfListener):
self.properties = {} # Extra data for other roles (i.e. arsonist)
def __repr__(self):
return self.__class__.__name__
return f"{self.__class__.__name__}({self.player.__repr__()})"
async def assign_player(self, player):
"""
@ -84,6 +84,8 @@ class Role(WolfListener):
player.role = self
self.player = player
log.debug(f"Assigned {self} to {player}")
async def get_alignment(self, source=None):
"""
Interaction for powerful access of alignment

@ -15,6 +15,7 @@ log = logging.getLogger("red.fox_v3.werewolf.role.seer")
class Seer(Role):
rand_choice = True
town_balance = 4
category = [
CATEGORY_TOWN_RANDOM,
CATEGORY_TOWN_INVESTIGATIVE,

@ -22,21 +22,6 @@ class VanillaWerewolf(Role):
"Vote to kill players at night with `[p]ww vote <ID>`"
)
def __init__(self, game):
super().__init__(game)
# 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)
# ]
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting

@ -7,12 +7,9 @@ log = logging.getLogger("red.fox_v3.werewolf.role.villager")
class Villager(Role):
# 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
@ -23,9 +20,6 @@ class Villager(Role):
"Lynch players during the day with `[p]ww vote <ID>`"
)
def __init__(self, game):
super().__init__(game)
async def see_alignment(self, source=None):
"""
Interaction for investigative roles attempting

@ -75,7 +75,6 @@ class VoteGroup(WolfListener):
if not self.players:
# TODO: Confirm deletion
self.game.to_delete.add(self)
pass
async def vote(self, target, author, target_id):

@ -1,9 +1,11 @@
import logging
from typing import List, Union
import discord
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.commands import Cog
from redbot.core.utils import AsyncIter
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
from werewolf.builder import (
@ -18,6 +20,14 @@ from werewolf.game import Game
log = logging.getLogger("red.fox_v3.werewolf")
async def anyone_has_role(
member_list: List[discord.Member], role: discord.Role
) -> Union[None, discord.Member]:
return await AsyncIter(member_list).find(
lambda m: AsyncIter(m.roles).find(lambda r: r.id == role.id)
)
class Werewolf(Cog):
"""
Base to host werewolf on a guild
@ -189,12 +199,15 @@ class Werewolf(Cog):
return
await game.join(ctx.author, ctx.channel)
await ctx.tick()
@commands.guild_only()
@ww.command(name="code")
async def ww_code(self, ctx: commands.Context, code):
"""
Adjust game code
Adjusts the game code.
See `[p]buildgame` to generate a new code
"""
game = await self._get_game(ctx)
@ -204,6 +217,7 @@ class Werewolf(Cog):
return
await game.set_code(ctx, code)
await ctx.tick()
@commands.guild_only()
@ww.command(name="quit")
@ -215,6 +229,7 @@ class Werewolf(Cog):
game = await self._get_game(ctx)
await game.quit(ctx.author, ctx.channel)
await ctx.tick()
@commands.guild_only()
@ww.command(name="start")
@ -229,6 +244,8 @@ class Werewolf(Cog):
if not await game.setup(ctx):
pass # ToDo something?
await ctx.tick()
@commands.guild_only()
@ww.command(name="stop")
async def ww_stop(self, ctx: commands.Context):
@ -245,6 +262,7 @@ class Werewolf(Cog):
game = await self._get_game(ctx)
game.game_over = True
await game.current_action.cancel()
await ctx.send("Game has been stopped")
@commands.guild_only()
@ -358,7 +376,7 @@ class Werewolf(Cog):
else:
await ctx.send("Role ID not found")
async def _get_game(self, ctx: commands.Context, game_code=None):
async def _get_game(self, ctx: commands.Context, game_code=None) -> Union[Game, None]:
guild: discord.Guild = getattr(ctx, "guild", None)
if guild is None:

Loading…
Cancel
Save