Implement votes
This commit is contained in:
		
							
								
								
									
										104
									
								
								orochi/bot.py
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								orochi/bot.py
									
									
									
									
									
								
							@@ -5,7 +5,7 @@ import logging
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from orochi import http
 | 
					from orochi import http
 | 
				
			||||||
from orochi.config import Config
 | 
					from orochi.config import Config
 | 
				
			||||||
from orochi.models import Game
 | 
					from orochi.models import Game, GameState, Player, RoundVote, Vote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bot = commands.Bot(command_prefix='!')
 | 
					bot = commands.Bot(command_prefix='!')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -182,6 +182,20 @@ async def on_ready():
 | 
				
			|||||||
    config.save()
 | 
					    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.")
 | 
					@bot.command(help="Envoyer un message en tant qu'Orochi.")
 | 
				
			||||||
@commands.has_permissions(administrator=True)
 | 
					@commands.has_permissions(administrator=True)
 | 
				
			||||||
async def send(ctx: commands.Context, *, message: str):
 | 
					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é.")
 | 
					    await ctx.message.reply("Message envoyé.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bot.command()
 | 
					@bot.command(help="Ouvrir les votes")
 | 
				
			||||||
async def vote(ctx: commands.Context):
 | 
					async def open(ctx: commands.Context):
 | 
				
			||||||
    view = Confirm()
 | 
					    game: Game = Game.INSTANCE
 | 
				
			||||||
    await ctx.message.reply("plop", view=view)
 | 
					    current_round = game.rounds[-1]
 | 
				
			||||||
    await view.wait()
 | 
					
 | 
				
			||||||
 | 
					    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 VoteView(disnake.ui.View):
 | 
				
			||||||
class Confirm(disnake.ui.View):
 | 
					 | 
				
			||||||
    @disnake.ui.button(label="S'allier", style=disnake.ButtonStyle.green)
 | 
					    @disnake.ui.button(label="S'allier", style=disnake.ButtonStyle.green)
 | 
				
			||||||
    async def confirm(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
 | 
					    async def confirm(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
 | 
				
			||||||
        self.clear_items()
 | 
					        await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True)
 | 
				
			||||||
        await interaction.response.edit_message(content="Vous vous êtes allié.", view=self)
 | 
					
 | 
				
			||||||
        self.stop()
 | 
					        self.vote(interaction, Vote.ALLY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @disnake.ui.button(label="Trahir", style=disnake.ButtonStyle.red)
 | 
					    @disnake.ui.button(label="Trahir", style=disnake.ButtonStyle.red)
 | 
				
			||||||
    async def cancel(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
 | 
					    async def cancel(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
 | 
				
			||||||
        self.clear_items()
 | 
					        await interaction.response.send_message("Votre vote a bien été pris en compte.", ephemeral=True)
 | 
				
			||||||
        await interaction.response.edit_message(content="Vous avez trahi.", view=self)
 | 
					
 | 
				
			||||||
        self.stop()
 | 
					        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():
 | 
					def run():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import pickle
 | 
				
			|||||||
from dataclasses import dataclass, field
 | 
					from dataclasses import dataclass, field
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
from enum import Enum
 | 
					from enum import Enum
 | 
				
			||||||
from typing import ClassVar
 | 
					from typing import ClassVar, Iterable, Generator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Room(Enum):
 | 
					class Room(Enum):
 | 
				
			||||||
@@ -28,7 +28,7 @@ class Player:
 | 
				
			|||||||
    private_channel_id: int = field(hash=False)
 | 
					    private_channel_id: int = field(hash=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def round_votes(self):
 | 
					    def round_votes(self) -> Generator["RoundVote", None, None]:
 | 
				
			||||||
        for r in Game.INSTANCE.rounds:
 | 
					        for r in Game.INSTANCE.rounds:
 | 
				
			||||||
            for room in r.rooms:
 | 
					            for room in r.rooms:
 | 
				
			||||||
                for vote in room.votes:
 | 
					                for vote in room.votes:
 | 
				
			||||||
@@ -36,7 +36,7 @@ class Player:
 | 
				
			|||||||
                        yield vote
 | 
					                        yield vote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def score(self):
 | 
					    def score(self) -> int:
 | 
				
			||||||
        s = 3
 | 
					        s = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for vote in self.round_votes:
 | 
					        for vote in self.round_votes:
 | 
				
			||||||
@@ -63,11 +63,13 @@ class RoundVote:
 | 
				
			|||||||
    timestamp: datetime | None = None
 | 
					    timestamp: datetime | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def players(self):
 | 
					    def players(self) -> Iterable[Player]:
 | 
				
			||||||
 | 
					        if self.player2 is None:
 | 
				
			||||||
 | 
					            return self.player1,
 | 
				
			||||||
        return self.player1, self.player2
 | 
					        return self.player1, self.player2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def room(self):
 | 
					    def room(self) -> "RoundRoom":
 | 
				
			||||||
        for r in Game.INSTANCE.rounds:
 | 
					        for r in Game.INSTANCE.rounds:
 | 
				
			||||||
            for room in r.rooms:
 | 
					            for room in r.rooms:
 | 
				
			||||||
                if self in room.votes:
 | 
					                if self in room.votes:
 | 
				
			||||||
@@ -84,6 +86,11 @@ class RoundRoom:
 | 
				
			|||||||
    def votes(self):
 | 
					    def votes(self):
 | 
				
			||||||
        return self.vote1, self.vote2
 | 
					        return self.vote1, self.vote2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def players(self) -> Generator[Player, None, None]:
 | 
				
			||||||
 | 
					        for vote in self.votes:
 | 
				
			||||||
 | 
					            yield from vote.players
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def round(self):
 | 
					    def round(self):
 | 
				
			||||||
        for r in Game.INSTANCE.rounds:
 | 
					        for r in Game.INSTANCE.rounds:
 | 
				
			||||||
@@ -99,7 +106,7 @@ class Round:
 | 
				
			|||||||
    room_c: RoundRoom
 | 
					    room_c: RoundRoom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def rooms(self):
 | 
					    def rooms(self) -> tuple[RoundRoom, RoundRoom, RoundRoom]:
 | 
				
			||||||
        return self.room_a, self.room_b, self.room_c
 | 
					        return self.room_a, self.room_b, self.room_c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,7 @@
 | 
				
			|||||||
                    {% endif %}
 | 
					                    {% endif %}
 | 
				
			||||||
                    <td>{{ vote.player1.name }}{% if vote.player2 %}, {{ vote.player2.name }}{% endif %}</td>
 | 
					                    <td>{{ vote.player1.name }}{% if vote.player2 %}, {{ vote.player2.name }}{% endif %}</td>
 | 
				
			||||||
                    {% if round.round != game.rounds|length or admin %}
 | 
					                    {% if round.round != game.rounds|length or admin %}
 | 
				
			||||||
                        <td>{{ room.vote1.vote.value|default('Pas de vote') }}</td>
 | 
					                        <td>{{ vote.vote.value|default('Pas de vote') }}</td>
 | 
				
			||||||
                    {% else %}
 | 
					                    {% else %}
 | 
				
			||||||
                        <td><em>Vote en cours ...</em></td>
 | 
					                        <td><em>Vote en cours ...</em></td>
 | 
				
			||||||
                    {% endif %}
 | 
					                    {% endif %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user