diff --git a/orochi/bot.py b/orochi/bot.py index cd5cfc4..19145e8 100644 --- a/orochi/bot.py +++ b/orochi/bot.py @@ -5,7 +5,7 @@ import logging from orochi import http from orochi.config import Config -from orochi.models import Game +from orochi.models import Game, GameState, Player, RoundVote, Vote bot = commands.Bot(command_prefix='!') @@ -182,6 +182,20 @@ async def on_ready(): config.save() +@bot.command(help="Sauvegarde la partie") +@commands.has_permissions(administrator=True) +async def save(ctx: commands.Context): + Game.INSTANCE.save('game.save') + await ctx.reply("La partie a été sauvegardée.") + + +@bot.command(help="Recharger la partie") +@commands.has_permissions(administrator=True) +async def load(ctx: commands.Context): + Game.load('game.save') + await ctx.reply("La partie a été rechargée.") + + @bot.command(help="Envoyer un message en tant qu'Orochi.") @commands.has_permissions(administrator=True) async def send(ctx: commands.Context, *, message: str): @@ -197,26 +211,88 @@ async def brother(ctx: commands.Context, *, message: str): await ctx.message.reply("Message envoyé.") -@bot.command() -async def vote(ctx: commands.Context): - view = Confirm() - await ctx.message.reply("plop", view=view) - await view.wait() +@bot.command(help="Ouvrir les votes") +async def open(ctx: commands.Context): + game: Game = Game.INSTANCE + current_round = game.rounds[-1] + + if game.state == GameState.VOTING: + await ctx.reply("Les votes sont déjà ouverts.") + return + elif game.state == GameState.RESULTS: + await ctx.reply("Les votes viennent d'être fermés, merci de démarrer un nouveau tour avec !prepare.") + return + + # Ensure that each room is configured + for room in current_round.rooms: + if room is None: + await ctx.reply("Les salles ne sont pas configurées.") + if len(list(room.players)) != 3: + await ctx.reply(f"La salle {room.room.value} ne contient pas trois joueurs, merci de la reconfigurer.") + + # Send messages to players + for room in current_round.rooms: + votes = list(room.votes) + for i, vote in enumerate(votes): + players = list(vote.players) + other_vote = votes[1 - i] + for j, player in enumerate(players): + other_player = players[1 - j] if len(players) == 2 else None + view = VoteView(timeout=3600) + channel_id = player.private_channel_id + channel = bot.get_channel(channel_id) + message = "Les votes sont ouverts.\n" + message += f"Vous devez aller voter en salle **{room.room.value}**.\n" + if other_player: + message += f"Vous êtes allié⋅e avec **{other_player.name}**.\n" + message += f"Vous affrontez {' et '.join(f'**{adv.name}**' for adv in other_vote.players)}.\n" + message += "Bonne chance !" + await channel.send(message) + + await channel.send("Pour voter, utilisez l'un des boutons ci-dessous. Vous pouvez appuyer " + "sur le bouton plusieurs fois, mais seul le premier vote sera enregistré.", + view=view) + + game.state = GameState.VOTING + + await ctx.reply("Les salles de vote sont ouvertes, les joueur⋅se⋅s peuvent désormais voter.") -# Define a simple View that gives us a confirmation menu -class Confirm(disnake.ui.View): +class VoteView(disnake.ui.View): @disnake.ui.button(label="S'allier", style=disnake.ButtonStyle.green) async def confirm(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction): - self.clear_items() - await interaction.response.edit_message(content="Vous vous êtes allié.", view=self) - self.stop() + await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True) + + self.vote(interaction, Vote.ALLY) @disnake.ui.button(label="Trahir", style=disnake.ButtonStyle.red) async def cancel(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction): - self.clear_items() - await interaction.response.edit_message(content="Vous avez trahi.", view=self) - self.stop() + await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True) + + self.vote(interaction, Vote.BETRAY) + + def vote(self, interaction: disnake.MessageInteraction, vote: Vote) -> None: + game = Game.INSTANCE + current_round = game.rounds[-1] + current_player: Player | None = None + for player in game.players.values(): + if player.private_channel_id == interaction.channel_id: + current_player = player + break + + current_vote: RoundVote | None = None + for room in current_round.rooms: + for v in room.votes: + if current_player in v.players: + current_vote = v + break + else: + continue + break + + if current_vote.vote is None: + current_vote.vote = vote + game.save('game.save') def run(): diff --git a/orochi/models.py b/orochi/models.py index 2f659b8..1f5adbf 100644 --- a/orochi/models.py +++ b/orochi/models.py @@ -2,7 +2,7 @@ import pickle from dataclasses import dataclass, field from datetime import datetime from enum import Enum -from typing import ClassVar +from typing import ClassVar, Iterable, Generator class Room(Enum): @@ -28,7 +28,7 @@ class Player: private_channel_id: int = field(hash=False) @property - def round_votes(self): + def round_votes(self) -> Generator["RoundVote", None, None]: for r in Game.INSTANCE.rounds: for room in r.rooms: for vote in room.votes: @@ -36,7 +36,7 @@ class Player: yield vote @property - def score(self): + def score(self) -> int: s = 3 for vote in self.round_votes: @@ -63,11 +63,13 @@ class RoundVote: timestamp: datetime | None = None @property - def players(self): + def players(self) -> Iterable[Player]: + if self.player2 is None: + return self.player1, return self.player1, self.player2 @property - def room(self): + def room(self) -> "RoundRoom": for r in Game.INSTANCE.rounds: for room in r.rooms: if self in room.votes: @@ -84,6 +86,11 @@ class RoundRoom: def votes(self): return self.vote1, self.vote2 + @property + def players(self) -> Generator[Player, None, None]: + for vote in self.votes: + yield from vote.players + @property def round(self): for r in Game.INSTANCE.rounds: @@ -99,7 +106,7 @@ class Round: room_c: RoundRoom @property - def rooms(self): + def rooms(self) -> tuple[RoundRoom, RoundRoom, RoundRoom]: return self.room_a, self.room_b, self.room_c diff --git a/orochi/templates/list.html b/orochi/templates/list.html index a3a10b0..d7b93ad 100644 --- a/orochi/templates/list.html +++ b/orochi/templates/list.html @@ -59,7 +59,7 @@ {% endif %} {{ vote.player1.name }}{% if vote.player2 %}, {{ vote.player2.name }}{% endif %} {% if round.round != game.rounds|length or admin %} - {{ room.vote1.vote.value|default('Pas de vote') }} + {{ vote.vote.value|default('Pas de vote') }} {% else %} Vote en cours ... {% endif %}