diff --git a/GameFiles/Game.py b/GameFiles/Game.py index 81382e1..567230c 100644 --- a/GameFiles/Game.py +++ b/GameFiles/Game.py @@ -1,13 +1,20 @@ import logging +import random from typing import Dict, Callable, List, Union from functools import wraps from collections import defaultdict +from enum import Enum import discord logger = logging.getLogger(__name__) +class Policy(Enum): + LIBERAL = "L" + FASCIST = "F" + + def game_started(func): """ Decorator for *methods* of Game that need the game to be started. @@ -113,6 +120,14 @@ class Game: def get_votes_channel(self) -> discord.TextChannel: return self.guild.get_channel(self.get_votes_channel_id()) + @game_started + def get_gm_channel_id(self) -> int: + return self.config["admin_chan"] + + @game_started + def get_gm_channel(self) -> discord.TextChannel: + return self.guild.get_channel(self.get_gm_channel_id()) + @game_started def is_vote_running(self) -> bool: return self.config["vote"] is not None @@ -143,6 +158,11 @@ class Game: self.config["players"] = [member.id for member in player_role.members] self.config["player_info"] = {str(player): {} for player in self.config["players"]} self.config["vote"] = None + self.config["deck"] = [Policy.FASCIST.value] * 11 + [Policy.LIBERAL.value] * 6 + random.shuffle(self.config["deck"]) + self.config["discard"] = [] + self.config["drawn"] = None + self.config["enacted"] = [] permissions = { self.guild.default_role: discord.PermissionOverwrite(send_messages = False), @@ -266,3 +286,28 @@ class Game: await self.get_announcements_channel().send("\n".join(announcement_content), allowed_mentions = discord.AllowedMentions(roles = True)) self.config["vote"] = None self.save_function() + + @game_started + async def draw_policies(self) -> List[Policy]: + self.config["drawn"] = [self.config["deck"].pop() for _ in range(3)] + self.save_function() + return [Policy(p) for p in self.config["drawn"]] + + async def enact_drawn_policy(self, index: int): + if self.config["drawn"] is None: + raise RuntimeError("Can only enact a policy when they have been drawn") + if not (0 <= index < len(self.config["drawn"])): + raise IndexError(f"Expected policy index between 0 and {len(self.config['drawn'])}, got {index}") + for i, policy_str in enumerate(self.config["drawn"]): + if i == index: + self.config["enacted"].append(policy_str) + else: + self.config["discard"].append(policy_str) + self.config["drawn"] = None + if len(self.config["deck"]) < 3: + self.config["deck"].extend(self.config["discard"]) + self.config["discard"] = [] + random.shuffle(self.config["deck"]) + self.save_function() + enacted = Policy(self.config["enacted"][-1]) + await self.get_announcements_channel().send(f"{self.get_player_role().mention} A **{enacted.name}** policy has been enacted!") diff --git a/GameFiles/__init__.py b/GameFiles/__init__.py index f633827..8f9ed25 100644 --- a/GameFiles/__init__.py +++ b/GameFiles/__init__.py @@ -1,2 +1,2 @@ -from .Game import Game +from .Game import Game, Policy from .GamesFile import GamesFile diff --git a/SecretBot.py b/SecretBot.py index 2443663..a530e6d 100755 --- a/SecretBot.py +++ b/SecretBot.py @@ -9,7 +9,7 @@ import discord.utils from discord.ext import commands import utils -from GameFiles import Game, GamesFile +from GameFiles import Game, GamesFile, Policy logger = logging.getLogger("SecretBot") @@ -174,6 +174,32 @@ class SecretBot(commands.Cog): await game.stop_vote() await ctx.message.delete() + @commands.command("Legislate") + async def draw_policies(self, ctx: commands.Context): + game = await self.get_running_game_or_error_message(ctx) + await self.check_is_administrator_or_gm(ctx) + if ctx.channel != game.get_gm_channel(): + await ctx.reply(":warning: You should do this in your own channel!") + return + policies = await game.draw_policies() + message_content = [ + "The following policies have been drawn:", + " ".join([f"{num + 1}) {':blue_square:' if policy == Policy.LIBERAL else ':red_square:'} " for num, policy in enumerate(policies)]), + "Send them to the president and chancellor and type `!Enact ` to enact one of them when you are finished" + ] + await ctx.reply("\n".join(message_content)) + + @commands.command("Enact") + async def enact_drawn_policy(self, ctx: commands.Context, policy_number: int): + game = await self.get_running_game_or_error_message(ctx) + await self.check_is_administrator_or_gm(ctx) + if ctx.channel != game.get_gm_channel(): + await ctx.reply(":warning: You should do this in your own channel!") + return + policy_number = policy_number - 1 + await game.enact_drawn_policy(policy_number) + await ctx.reply(":white_check_mark: Done") + if __name__ == '__main__': argparser = argparse.ArgumentParser(description = "Secret Hitler helper bot", formatter_class = argparse.ArgumentDefaultsHelpFormatter)