Added start vote and fixed deocrator bug

This commit is contained in:
Elnath 2021-06-10 00:37:25 +02:00
parent 27c45f863f
commit 5f20403b9b
2 changed files with 102 additions and 4 deletions

View File

@ -1,6 +1,7 @@
import logging import logging
from typing import Dict, Callable, List, Union from typing import Dict, Callable, List, Union
from functools import wraps from functools import wraps
from collections import defaultdict
import discord import discord
@ -11,11 +12,27 @@ def started_only(func):
""" """
Decorator for *methods* of Game that need the game to be started. Decorator for *methods* of Game that need the game to be started.
""" """
@wraps(func) @wraps(func)
def decorated(obj, *args, **kwargs): def decorated(obj: 'Game', *args, **kwargs):
if not obj.is_started(): if not obj.is_started():
raise RuntimeError("This function only works on running games!") raise RuntimeError("This function only works on running games!")
func(obj, *args, **kwargs) return func(obj, *args, **kwargs)
return decorated
def vote_running(func):
"""
Decorator for *methods* of Game that need a vote to be running
"""
@wraps(func)
def decorated(obj: 'Game', *args, **kwargs):
if not obj.is_vote_running():
raise RuntimeError("This function only works if a vote is running!")
return func(obj, *args, **kwargs)
return decorated return decorated
@ -72,6 +89,25 @@ class Game:
def get_game_category(self) -> discord.CategoryChannel: def get_game_category(self) -> discord.CategoryChannel:
return self.guild.get_channel(self.get_game_category_id()) return self.guild.get_channel(self.get_game_category_id())
@started_only
def get_votes_channel_id(self) -> int:
return self.config["votes_chan"]
@started_only
def get_votes_channel(self) -> discord.TextChannel:
return self.guild.get_channel(self.get_votes_channel_id())
@started_only
def is_vote_running(self) -> bool:
return self.config["vote"] is not None
@vote_running
def is_vote_passing(self) -> bool:
vote_count = defaultdict(int)
for player_id in self.get_players_id():
vote_count[self.config["vote"][str(player_id)]] += 1
return vote_count[True] > vote_count[False]
async def start(self, gm_role: discord.Role, player_role: discord.Role): async def start(self, gm_role: discord.Role, player_role: discord.Role):
if self.is_started(): if self.is_started():
raise ValueError("Game already started") raise ValueError("Game already started")
@ -80,6 +116,7 @@ class Game:
self.config["player_role"] = player_role.id self.config["player_role"] = player_role.id
self.config["players"] = [member.id for member in player_role.members] 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["player_info"] = {str(player): {} for player in self.config["players"]}
self.config["vote"] = None
permissions = { permissions = {
self.guild.default_role: discord.PermissionOverwrite(send_messages = False), self.guild.default_role: discord.PermissionOverwrite(send_messages = False),
@ -108,14 +145,14 @@ class Game:
self.config["discussion_chan"] = (await game_category.create_text_channel("discussion")).id # Permissions are inherited from the category self.config["discussion_chan"] = (await game_category.create_text_channel("discussion")).id # Permissions are inherited from the category
logger.debug(f"[{self.guild.name}] Created discussion channel") logger.debug(f"[{self.guild.name}] Created discussion channel")
for player in self.get_players(): for player in player_role.members:
channel_permissions = { channel_permissions = {
self.guild.default_role: discord.PermissionOverwrite(read_messages = False), self.guild.default_role: discord.PermissionOverwrite(read_messages = False),
player: discord.PermissionOverwrite(read_messages = True), player: discord.PermissionOverwrite(read_messages = True),
gm_role: discord.PermissionOverwrite(read_messages = True), gm_role: discord.PermissionOverwrite(read_messages = True),
} }
player_channel = await game_category.create_text_channel(player.name, overwrites = channel_permissions) player_channel = await game_category.create_text_channel(player.name, overwrites = channel_permissions)
self.get_player_info(player)["channel"] = player_channel.id self.config["player_info"][str(player.id)]["channel"] = player_channel.id
logger.debug(f"[{self.guild.name}] Created player channels") logger.debug(f"[{self.guild.name}] Created player channels")
self.config["game_started"] = True self.config["game_started"] = True
@ -130,3 +167,52 @@ class Game:
self.config.clear() self.config.clear()
self.config.update(self.new_dict()) self.config.update(self.new_dict())
self.save_function() self.save_function()
async def start_vote(self, president: discord.Member, chancellor: discord.Member):
if self.is_vote_running():
raise RuntimeError("A vote is already running")
logging.debug(f"[{self.guild.name}] Starting vote")
self.config["vote"] = {
"president": president.id,
"chancellor": chancellor.id,
"message": None,
"revealed": False,
}
self.config["vote"].update({str(player_id): None for player_id in self.get_players_id()})
self.save_function()
await self.update_vote_message()
@vote_running
async def update_vote_message(self):
logging.debug(f"[{self.guild.name}] Updating vote message")
president = self.config["vote"]["president"]
chancellor = self.config["vote"]["chancellor"]
message_content = [
"**Citizens are called to vote**",
"Do you want to elect the following government?",
f":crown: <@{president}> as president",
f":person_in_tuxedo: <@{chancellor}> as chancellor",
"",
]
for player_id in self.get_players_id():
player_vote = self.config["vote"][str(player_id)]
if player_vote is None:
message_content.append(f":black_large_square: <@{player_id}> has not voted")
else:
if self.config["vote"]["revealed"]:
if player_vote:
message_content.append(f":green_square: <@{player_id}> has voted JA")
else:
message_content.append(f":red_square: <@{player_id}> has voted NEIN")
else: # Player has voted but the vote should not be revealed
message_content.append(f":white_large_square: <@{player_id}> has voted")
message_content_str = "\n".join(message_content)
if self.config["vote"]["message"] is None:
self.config["vote"]["message"] = (await self.get_votes_channel().send(message_content_str, allowed_mentions = discord.AllowedMentions.none())).id
else:
await (await self.get_votes_channel().fetch_message(self.config["vote"]["message"])).edit(content = message_content_str, allowed_mentions = discord.AllowedMentions.none())

View File

@ -114,6 +114,18 @@ class SecretBot(commands.Cog):
else: else:
await ctx.reply(":x: Game is not running") await ctx.reply(":x: Game is not running")
@commands.command("StartVote")
async def start_vote(self, ctx:commands.Context, president: discord.Member, chancellor: discord.Member):
game = self.games_file[ctx.guild]
if not game.is_started():
await ctx.reply(":x: Game is not running")
return
if game.is_vote_running():
await ctx.reply(":x: A vote is already running")
return
await game.start_vote(president, chancellor)
await ctx.message.delete()
if __name__ == '__main__': if __name__ == '__main__':
argparser = argparse.ArgumentParser(description = "Secret Hitler helper bot", formatter_class = argparse.ArgumentDefaultsHelpFormatter) argparser = argparse.ArgumentParser(description = "Secret Hitler helper bot", formatter_class = argparse.ArgumentDefaultsHelpFormatter)