From 130f11422a7374133abcfefd0ca442afe495208a Mon Sep 17 00:00:00 2001 From: Bobloy Date: Mon, 2 Apr 2018 17:00:24 -0400 Subject: [PATCH] today's progress p_channels from secret_channels decisions on how to register a channel/votegroup without accidently duplication --- werewolf/Game.py | 115 +++++++++++++++++++++--------- werewolf/Role.py | 3 +- werewolf/Roles/VanillaWerewolf.py | 16 +++-- werewolf/Roles/Villager.py | 76 +++++++++++--------- werewolf/VoteGroup.py | 31 ++++---- werewolf/VoteGroups/WolfVote.py | 27 +++---- werewolf/Werewolf.py | 10 +-- 7 files changed, 168 insertions(+), 110 deletions(-) diff --git a/werewolf/Game.py b/werewolf/Game.py index 7c91037..7d7a3d2 100644 --- a/werewolf/Game.py +++ b/werewolf/Game.py @@ -12,14 +12,23 @@ class Game: """ Base class to run a single game of Werewolf """ + + default_secret_channel = { + "channel": None, + "players": [], + "votegroup": None + } + def __new__(cls, game_code): game_code = ["DefaultWerewolf", "Villager", "Villager""] return Game(game_code) - def __init__(self, game_code): - self.roles = [] + def __init__(self, guild, game_code): + self.guild = guild self.game_code = game_code + self.roles = [] + if self.game_code: self.get_roles() @@ -30,9 +39,11 @@ class Game: self.game_over = False self.can_vote = False + self.channel_category = None self.village_channel = None - self.secret_channels = {} - self.vote_groups = [] + + self.p_channels = {} + self.vote_groups = {} self.loop = asyncio.get_event_loop() @@ -48,16 +59,51 @@ class Game: 4. Start game """ if len(self.players) != self.roles: - ctx.send("Players does not match roles, cannot start") + ctx.send("Player count does not match role count, cannot start") return False + overwrite = { + self.guild.default_role: discord.PermissionOverwrite(read_messages=False), + self.guild.me: discord.PermissionOverwrite(read_messages=True) + } + + self.channel_category = await self.guild.create_category("ww-game", overwrites=overwrite, reason="New game of werewolf") + + for player in self.players: + overwrite[player.member] = discord.PermissionOverwrite(read_messages=True) + + self.village_channel = await self.guild.create_text_channel("Village Square", overwrites=overwrite, reason="New game of werewolf", category=self.channel_category) + + # Assuming everything worked so far + await self._at_day_start() # This will queue channels and votegroups to be made + + for channel_id in self.p_channels: + overwrite = { + self.guild.default_role: discord.PermissionOverwrite(read_messages=False), + self.guild.me: discord.PermissionOverwrite(read_messages=True) + } + + for member in self.p_channels[channel_id]["players"]: + overwrite[member] = discord.PermissionOverwrite(read_messages=True) + + channel = await self.guild.create_text_channel(channel_id, overwrites=overwrite, reason="Werewolf secret channel", category=self.channel_category) + + self.p_channels[channel_id]["channel"] = channel + + if self.p_channels[channel_id]["votegroup"] is not None: + vote_group = self.p_channels[channel_id]["votegroup"](self, channel) + + await vote_group.register_player() + self.vote_groups[channel_id] = self.p_channels[channel_id]["votegroup"](self, channel) + + ############START Notify structure############ async def _cycle(self): """ Each event calls the next event - _at_start() + _at_day_start() _at_voted() _at_kill() @@ -65,17 +111,17 @@ class Game: _at_night_begin() _at_night_end() - and repeat with _at_morning_start() again + and repeat with _at_day_start() again """ - await self._at_start(): + await self._at_day_start(): async def _at_game_start(self): # ID 0 if self.game_over: return - await self._notify(0) + await self.village_channel.send("Game is starting, please wait for setup to complete") - asyncio.sleep(60) - await self._at_day_start() + await self._notify(0) + async def _at_day_start(self): # ID 1 if self.game_over: @@ -90,17 +136,20 @@ class Game: async def _at_voted(self, target): # ID 2 if self.game_over: return - await self._notify(2, target) + data = {"player": target} + await self._notify(2, data) async def _at_kill(self, target): # ID 3 if self.game_over: return - await self._notify(3, target) + data = {"player": target} + await self._notify(3, data) async def _at_hang(self, target): # ID 4 if self.game_over: return - await self._notify(4, target) + data = {"player": target} + await self._notify(4, data) async def _at_day_end(self): # ID 5 if self.game_over: @@ -142,7 +191,7 @@ class Game: for role in role_order: tasks.append(asyncio.ensure_future(role.on_event(event, data)) # VoteGroup priorities - vote_order = [votes for votes in self.vote_groups if votes.action_list[event][1]==i] + vote_order = [votes for votes in self.vote_groups.values() if votes.action_list[event][1]==i] for vote_group in vote_order: tasks.append(asyncio.ensure_future(vote_group.on_event(event, data)) @@ -163,17 +212,22 @@ class Game: embed.add_field(name="ID# **{}**".format(i), value="{} {}".format(status, player.member.display_name), inline=True) return await channel.send(embed=embed) + + + async def register_channel(self, channel_id, player, votegroup=None): + """ + Queue a channel to be created by game_start + """ + if channel_id not in self.p_channels: + self.p_channels[channel_id] = self.default_secret_channel.copy() - async def register_channel(self, channel_id, votegroup = None): - # Create channel, set permissions, register votegroup - if channel_id not in self.secret_channels: - + await asyncio.sleep(1) - async def register_vote_group(self, channel_id, votegroup = None): - # Register channel and assign passed votegroup to it - if channel_id not in self.secret_channels: - await self.register_channel(channel_id, votegroup(self)) - + self.p_channels[channel_id]["players"].append(player) + + if votegroup: + self.p_channels[channel_id]["votegroup"] = votegroup + async def join(self, member: discord.Member, channel: discord.Channel): """ Have a member join a game @@ -201,13 +255,6 @@ class Game: if self.started: await self.kill() - - if member in self.players: - return "{} is already in the game!".format(member.mention) - - self.started.append(member) - - channel.send("{} has been added to the game, total players is **{}**".format(member.mention, len(self.players))) async def vote(self, author, id, channel): """ @@ -222,15 +269,14 @@ class Game: if not player.alive: channel.send("Corpses can't vote") return - - if channel in self.secret_channels.values(): if channel == self.village_channel: if not self.can_vote: channel.send("Voting is not allowed right now") return - + if channel in self.p_channels.values(): + try: target = self.players[id] except IndexError: @@ -244,6 +290,7 @@ class Game: """ Attempt to kill a target Source allows admin override + Be sure to remove permissions appropriately """ async def get_roles(self, game_code=None): diff --git a/werewolf/Role.py b/werewolf/Role.py index bf96957..b7ef4e5 100644 --- a/werewolf/Role.py +++ b/werewolf/Role.py @@ -67,7 +67,6 @@ class Role: self.game = game self.player = None self.blocked = False - self.secret_channel = None self.properties = {} # Extra data for other roles (i.e. arsonist) async def on_event(self, event, data): @@ -103,7 +102,7 @@ class Role: async def _at_game_start(self, data=None): if self.channel_id: - self.properties["channel"] = await self.game.register_channel(self.channel_id) + await self.game.register_channel(self.channel_id, self) await self.player.send_dm(self.game_start_message) #Maybe embeds eventually diff --git a/werewolf/Roles/VanillaWerewolf.py b/werewolf/Roles/VanillaWerewolf.py index 1335b93..394a575 100644 --- a/werewolf/Roles/VanillaWerewolf.py +++ b/werewolf/Roles/VanillaWerewolf.py @@ -33,11 +33,11 @@ class VanillaWerewolf(Role): (self._at_night_end, 5) ] - def __init__(self, game): - self.game = game - self.player = None - self.blocked = False - self.properties = {} # Extra data for other roles (i.e. arsonist) + # def __init__(self, game): + # self.game = game + # self.player = None + # self.blocked = False + # self.properties = {} # Extra data for other roles (i.e. arsonist) # async def on_event(self, event, data): # """ @@ -70,9 +70,11 @@ class VanillaWerewolf(Role): return "Werewolf" async def _at_game_start(self, data=None): - # super()._at_game_start(data) # Registers channel + if self.channel_id: + await self.game.register_channel(self.channel_id, self, WolfVote) # Add VoteGroup WolfVote + + await self.player.send_dm(self.game_start_message) - await self.game.register_vote_group(self.channel_id, WolfVote) # async def _at_day_start(self, data=None): # super()._at_day_start(data) diff --git a/werewolf/Roles/Villager.py b/werewolf/Roles/Villager.py index e585ce8..f91f2c9 100644 --- a/werewolf/Roles/Villager.py +++ b/werewolf/Roles/Villager.py @@ -11,6 +11,11 @@ class Villager(Role): allignment = 0 # 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=""" + Your role is **Villager** + You win by lynching all evil in the town + Lynch players during the day with `[p]ww lynch ` + """ action_list = [ (self._at_game_start, 0), # (Action, Priority) (self._at_day_start, 0), @@ -22,63 +27,64 @@ class Villager(Role): (self._at_night_end, 0) ] - def __init__(self, game): - self.game = game - self.player = None - self.blocked = False - self.properties = {} # Extra data for other roles (i.e. arsonist) + # def __init__(self, game): + # self.game = game + # self.player = None + # self.blocked = False + # self.secret_channel = None + # self.properties = {} # Extra data for other roles (i.e. arsonist) - async def on_event(self, event, data): - """ - See Game class for event guide - """ + # async def on_event(self, event, data): + # """ + # See Game class for event guide + # """ - await action_list[event][0](data) + # await action_list[event][0](data) - async def assign_player(self, player): - """ - Give this role a player - Can be used after the game has started (Cult, Mason, other role swap) - """ + # async def assign_player(self, player): + # """ + # Give this role a player + # Can be used after the game has started (Cult, Mason, other role swap) + # """ - player.role = self - self.player = player + # player.role = self + # self.player = player async def _get_role(self, source=None): """ Interaction for powerful access of role Unlikely to be able to deceive this """ - return "Default" + return "Villager" async def _see_role(self, source=None): """ Interaction for investigative roles. More common to be able to deceive these roles """ - return "Role" + return "Villager" - async def _at_game_start(self, data=None): - pass + # async def _at_game_start(self, data=None): + # pass - async def _at_day_start(self, data=None): - pass + # async def _at_day_start(self, data=None): + # pass - async def _at_voted(self, target=None): - pass + # async def _at_voted(self, target=None): + # pass - async def _at_kill(self, target=None): - pass + # async def _at_kill(self, target=None): + # pass - async def _at_hang(self, target=None): - pass + # async def _at_hang(self, target=None): + # pass - async def _at_day_end(self): - pass + # async def _at_day_end(self): + # pass - async def _at_night_start(self): - pass + # async def _at_night_start(self): + # pass - async def _at_night_end(self): - pass + # async def _at_night_end(self): + # pass diff --git a/werewolf/VoteGroup.py b/werewolf/VoteGroup.py index 163b216..04e9ba1 100644 --- a/werewolf/VoteGroup.py +++ b/werewolf/VoteGroup.py @@ -26,10 +26,10 @@ class VoteGroup: ] - def __init__(self, game, members): + def __init__(self, game, channel): self.game = game - self.members = members - self.channel = None + self.channel = channel + self.players = [] self.vote_results = {} self.properties = {} # Extra data for other options @@ -42,8 +42,7 @@ class VoteGroup: await action_list[event][0](data) async def _at_game_start(self, data=None): - if self.channel_id: - self.channel = await self.game.register_channel(self.channel_id) + pass async def _at_day_start(self, data=None): pass @@ -52,11 +51,13 @@ class VoteGroup: pass async def _at_kill(self, data=None): - pass + if data["player"] in self.players: + self.players.pop(data["player"]) async def _at_hang(self, data=None): - pass - + if data["player"] in self.players: + self.players.pop(data["player"]) + async def _at_day_end(self, data=None): pass @@ -80,18 +81,18 @@ class VoteGroup: # Do what you voted on pass - async def register_member(self, member): + async def register_player(self, player): """ - Add a member to member list + Add a player to player list """ - self.members.append(member) + self.players.append(player) - async def remove_member(self, member): + async def remove_player(self, player): """ - Remove a member from member list + Remove a player from player list """ - if member in self.members: - self.members.remove(member) + if player.id in self.players: + self.players.remove(player) async def vote(self, author, id): """ diff --git a/werewolf/VoteGroups/WolfVote.py b/werewolf/VoteGroups/WolfVote.py index 7a57df5..2420288 100644 --- a/werewolf/VoteGroups/WolfVote.py +++ b/werewolf/VoteGroups/WolfVote.py @@ -27,16 +27,17 @@ class WolfVote(VoteGroup): kill_messages = [ - "{target} was attacked by wolves", - "{target} was found torn to shreds"] + "**{ID}** - {target} was attacked by wolves", + "**{ID}** - {target} was found torn to shreds"] - def __init__(self, game, members): - self.game = game - self.members = members - self.channel = None - self.vote_results = {} - self.properties = {} # Extra data for other options + def __init__(self, game, channel): + # self.game = game + # self.channel = channel + # self.players = [] + # self.vote_results = {} + # self.properties = {} # Extra data for other options self.killer = None # Added killer + super().__init__(game, channel) # async def on_event(self, event, data): @@ -57,10 +58,12 @@ class WolfVote(VoteGroup): # pass # async def _at_kill(self, data=None): - # pass + # if data["player"] in self.players: + # self.players.pop(data["player"]) # async def _at_hang(self, data=None): - # pass + # if data["player"] in self.players: + # self.players.pop(data["player"]) # async def _at_day_end(self, data=None): # pass @@ -71,7 +74,7 @@ class WolfVote(VoteGroup): await self.game.generate_targets(self.channel) - self.killer = random.choice(self.members) + self.killer = random.choice(self.players) await channel.send("{} has been selected as tonight's killer") @@ -93,4 +96,4 @@ class WolfVote(VoteGroup): # Receive vote from game # """ - # self.vote_results[author.id] = id \ No newline at end of file + # self.vote_results[author.id] = id diff --git a/werewolf/Werewolf.py b/werewolf/Werewolf.py index bdd2eda..d359a85 100644 --- a/werewolf/Werewolf.py +++ b/werewolf/Werewolf.py @@ -11,7 +11,7 @@ from .game import Game class Werewolf: """ - Base to host werewolf on a server + Base to host werewolf on a guild """ def __init__(self, bot): @@ -25,7 +25,7 @@ class Werewolf: self.config.register_global(**default_global) self.config.register_guild(**default_guild) - self.games = {} # Active games stored here, id is per server + self.games = {} # Active games stored here, id is per guild @commands.group() async def ww(self, ctx: commands.Context): @@ -44,7 +44,7 @@ class Werewolf: game = self._get_game(ctx.guild, game_code) if not game: - ctx.send(" + ctx.send("Failed to start a new game") @ww.command() async def join(self, ctx): @@ -84,14 +84,14 @@ class Werewolf: if channel is game.village_channel: await game.vote(ctx.author, id, channel) - if channel in (c for id,c in game.secret_channels.items()): + if channel in (c["channel"] for c in game.p_channels.values()): await game.vote(ctx.author, id, channel) def _get_game(self, guild, game_code = None): if guild.id not in self.games: if not game_code: return None - self.games[guild.id] = Game(game_code) + self.games[guild.id] = Game(guild, game_code) return self.games[guild.id]