Implement round preparation
This commit is contained in:
parent
de6dc03dda
commit
388c729235
180
orochi/bot.py
180
orochi/bot.py
|
@ -1,3 +1,5 @@
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
import disnake
|
import disnake
|
||||||
from disnake import CategoryChannel, PermissionOverwrite, TextChannel
|
from disnake import CategoryChannel, PermissionOverwrite, TextChannel
|
||||||
from disnake.ext import commands
|
from disnake.ext import commands
|
||||||
|
@ -5,7 +7,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, GameState, Player, RoundVote, Vote
|
from orochi.models import Game, GameState, Player, RoundVote, Vote, Round, RoundRoom, Room
|
||||||
|
|
||||||
bot = commands.Bot(command_prefix='!')
|
bot = commands.Bot(command_prefix='!')
|
||||||
|
|
||||||
|
@ -221,15 +223,16 @@ async def open(ctx: commands.Context):
|
||||||
await ctx.reply("Les votes sont déjà ouverts.")
|
await ctx.reply("Les votes sont déjà ouverts.")
|
||||||
return
|
return
|
||||||
elif game.state == GameState.RESULTS:
|
elif game.state == GameState.RESULTS:
|
||||||
await ctx.reply("Les votes viennent d'être fermés, merci de démarrer un nouveau tour avec !prepare.")
|
await ctx.reply("Les votes viennent d'être fermés, merci de démarrer un nouveau tour avec `!prepare`.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Ensure that each room is configured
|
# Ensure that each room is configured
|
||||||
for room in current_round.rooms:
|
for room in current_round.rooms:
|
||||||
if room is None:
|
if room is None:
|
||||||
await ctx.reply("Les salles ne sont pas configurées.")
|
await ctx.reply("Les salles ne sont pas configurées.")
|
||||||
if len(list(room.players)) != 3:
|
if len(list(room.players)) != 3 or not all(player for player in room.players):
|
||||||
await ctx.reply(f"La salle {room.room.value} ne contient pas trois joueurs, merci de la reconfigurer.")
|
return await ctx.reply(f"La salle {room.room.value} ne contient pas trois joueurs, "
|
||||||
|
f"merci de finir sa configuration avec `!setup {room.room.value}`.")
|
||||||
|
|
||||||
# Send messages to players
|
# Send messages to players
|
||||||
for room in current_round.rooms:
|
for room in current_round.rooms:
|
||||||
|
@ -267,13 +270,15 @@ async def close(ctx: commands.Context):
|
||||||
await ctx.reply("Les votes ne sont pas ouverts.")
|
await ctx.reply("Les votes ne sont pas ouverts.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
game.state = GameState.RESULTS
|
||||||
|
|
||||||
current_round = game.rounds[-1]
|
current_round = game.rounds[-1]
|
||||||
for room in current_round.rooms:
|
for room in current_round.rooms:
|
||||||
for vote in room.votes:
|
for vote in room.votes:
|
||||||
if vote.vote is None:
|
if vote.vote is None:
|
||||||
vote.vote = Vote.ALLY
|
vote.vote = Vote.ALLY
|
||||||
await ctx.send(f"L'équipe **{' et '.join(player.name for player in vote.players)}** "
|
await ctx.send(f"L'équipe **{' et '.join(player.name for player in vote.players)}** "
|
||||||
f"n'a pas voté en salle {room.room.value} et s'est alliée par défaut.")
|
f"n'a pas voté en salle **{room.room.value}** et s'est alliée par défaut.")
|
||||||
|
|
||||||
for player in game.players.values():
|
for player in game.players.values():
|
||||||
channel = bot.get_channel(player.private_channel_id)
|
channel = bot.get_channel(player.private_channel_id)
|
||||||
|
@ -283,10 +288,79 @@ async def close(ctx: commands.Context):
|
||||||
await channel.send("Tiens ! Vous êtes morts :)")
|
await channel.send("Tiens ! Vous êtes morts :)")
|
||||||
|
|
||||||
await ctx.reply("Les votes ont bien été fermés.")
|
await ctx.reply("Les votes ont bien été fermés.")
|
||||||
game.state = GameState.RESULTS
|
|
||||||
game.save('game.save')
|
game.save('game.save')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(help="Préparation du tour suivant")
|
||||||
|
@commands.has_permissions(administrator=True)
|
||||||
|
async def prepare(ctx: commands.Context):
|
||||||
|
game: Game = Game.INSTANCE
|
||||||
|
if game.state != GameState.RESULTS:
|
||||||
|
await ctx.reply("Le tour actuel n'est pas terminé.")
|
||||||
|
return
|
||||||
|
|
||||||
|
game.state = GameState.PREPARING
|
||||||
|
game.rounds.append(Round(
|
||||||
|
round=len(game.rounds) + 1,
|
||||||
|
room_a=RoundRoom(
|
||||||
|
room=Room.A,
|
||||||
|
vote1=RoundVote(),
|
||||||
|
vote2=RoundVote(),
|
||||||
|
),
|
||||||
|
room_b=RoundRoom(
|
||||||
|
room=Room.B,
|
||||||
|
vote1=RoundVote(),
|
||||||
|
vote2=RoundVote(),
|
||||||
|
),
|
||||||
|
room_c=RoundRoom(
|
||||||
|
room=Room.C,
|
||||||
|
vote1=RoundVote(),
|
||||||
|
vote2=RoundVote(),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
game.save('game.save')
|
||||||
|
|
||||||
|
await ctx.reply("Le tour suivant est en préparation. Utilisez `!setup A|B|C` pour paramétrer les salles A, B ou C. "
|
||||||
|
"Dan peut faire la même chose.")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(help="Prévisualisation des combats d'un tour")
|
||||||
|
@commands.has_any_role('IA', 'Dan')
|
||||||
|
async def preview(ctx: commands.Context):
|
||||||
|
game: Game = Game.INSTANCE
|
||||||
|
current_round = game.rounds[-1]
|
||||||
|
for room in current_round.rooms:
|
||||||
|
await ctx.send(f"Dans la salle **{room.room.value}**, s'affronteront :\n"
|
||||||
|
f"- **{' et '.join(str(player or '_personne_') for player in room.vote1.players)}**\n"
|
||||||
|
f"- **{' et '.join(str(player or '_personne_') for player in room.vote2.players)}**")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.command(help="Préparation d'une salle")
|
||||||
|
@commands.has_any_role('IA', 'Dan')
|
||||||
|
async def setup(ctx: commands.Context, room: Room):
|
||||||
|
game: Game = Game.INSTANCE
|
||||||
|
current_round = game.rounds[-1]
|
||||||
|
|
||||||
|
if game.state != GameState.PREPARING:
|
||||||
|
return await ctx.reply("Vous ne pouvez pas préparer la salle avant le tour suivant.")
|
||||||
|
|
||||||
|
await ctx.reply(f"Préparation de la salle {room.value}.")
|
||||||
|
|
||||||
|
match room:
|
||||||
|
case Room.A:
|
||||||
|
round_room = current_round.room_a
|
||||||
|
case Room.B:
|
||||||
|
round_room = current_round.room_b
|
||||||
|
case _:
|
||||||
|
round_room = current_round.room_c
|
||||||
|
|
||||||
|
view = PrepareRoomView(round_room, 0, timeout=300)
|
||||||
|
await ctx.send(f"Veuillez choisir qui s'affrontera seul dans la salle **{room.value}**.", view=view)
|
||||||
|
|
||||||
|
if round_room.vote1.player1 is not None:
|
||||||
|
await ctx.send(f"Attention : **{round_room.vote1.player1.name}** est déjà choisie.")
|
||||||
|
|
||||||
|
|
||||||
class VoteView(disnake.ui.View):
|
class VoteView(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):
|
||||||
|
@ -330,6 +404,100 @@ class VoteView(disnake.ui.View):
|
||||||
game.save('game.save')
|
game.save('game.save')
|
||||||
|
|
||||||
|
|
||||||
|
class PrepareRoomView(disnake.ui.View):
|
||||||
|
def __init__(self, round_room: RoundRoom, player_id: int, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
assert 0 <= player_id < 3
|
||||||
|
self.round_room = round_room
|
||||||
|
self.player_id = player_id
|
||||||
|
|
||||||
|
for player_name in Config.PLAYERS:
|
||||||
|
async def choose_player(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
|
||||||
|
game: Game = Game.INSTANCE
|
||||||
|
player = game.players[button.label]
|
||||||
|
current_round = game.rounds[-1]
|
||||||
|
for room in current_round.rooms:
|
||||||
|
for vote in room.votes:
|
||||||
|
if player in vote.players:
|
||||||
|
replaced_player = None
|
||||||
|
if room == self.round_room:
|
||||||
|
match self.player_id:
|
||||||
|
case 0:
|
||||||
|
replaced_player = room.vote1.player1
|
||||||
|
case 1:
|
||||||
|
replaced_player = room.vote2.player1
|
||||||
|
case 2:
|
||||||
|
replaced_player = room.vote2.player2
|
||||||
|
|
||||||
|
if replaced_player != player:
|
||||||
|
await interaction.send(
|
||||||
|
f"Attention : **{player.name}** était déjà attribué⋅e dans la salle "
|
||||||
|
f"**{room.room.value}**. Vous devrez probablement la re-configurer.")
|
||||||
|
|
||||||
|
if vote.player1 == player:
|
||||||
|
vote.player1 = None
|
||||||
|
elif vote.player2 == player:
|
||||||
|
vote.player2 = None
|
||||||
|
|
||||||
|
self.clear_items()
|
||||||
|
await interaction.send("Choix bien pris en compte.")
|
||||||
|
await interaction.edit_original_message(view=self)
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
match self.player_id:
|
||||||
|
case 0:
|
||||||
|
self.round_room.vote1.player1 = player
|
||||||
|
|
||||||
|
view = PrepareRoomView(self.round_room, 1, timeout=300)
|
||||||
|
await interaction.send(
|
||||||
|
f"**{player.name}** se battra seul⋅e. Veuillez désormais choisir contre qui "
|
||||||
|
"il ou elle se battra.", view=view)
|
||||||
|
if self.round_room.vote2.player1 is not None:
|
||||||
|
await interaction.send(
|
||||||
|
f"Attention : **{self.round_room.vote2.player1.name}** est déjà choisi⋅e."
|
||||||
|
)
|
||||||
|
case 1:
|
||||||
|
self.round_room.vote2.player1 = player
|
||||||
|
|
||||||
|
view = PrepareRoomView(self.round_room, 2, timeout=300)
|
||||||
|
await interaction.send(
|
||||||
|
f"**{player.name}** se battra contre **{self.round_room.vote1.player1.name}**. "
|
||||||
|
"Veuillez désormais choisir son partenaire.",
|
||||||
|
view=view)
|
||||||
|
if self.round_room.vote2.player2 is not None:
|
||||||
|
await interaction.send(
|
||||||
|
f"Attention : **{self.round_room.vote2.player2.name}** est déjà choisi⋅e."
|
||||||
|
)
|
||||||
|
case 2:
|
||||||
|
self.round_room.vote2.player2 = player
|
||||||
|
await interaction.send(
|
||||||
|
f"Dans la salle **{round_room.room.value}**, **{round_room.vote1.player1.name}** "
|
||||||
|
f"affrontera **{round_room.vote2.player1.name}** et **{round_room.vote2.player2.name}**.")
|
||||||
|
await interaction.send(
|
||||||
|
"Vous pouvez redéfinir la salle tant que le tour n'est pas lancé. "
|
||||||
|
"Utilisez !preview pour un récapitulatif des tours.")
|
||||||
|
|
||||||
|
game.save('game.save')
|
||||||
|
|
||||||
|
game: Game = Game.INSTANCE
|
||||||
|
current_round = game.rounds[-1]
|
||||||
|
for room in current_round.rooms:
|
||||||
|
for player in room.players:
|
||||||
|
if player is not None and player.name == player_name:
|
||||||
|
style = disnake.ButtonStyle.danger
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
style = disnake.ButtonStyle.primary
|
||||||
|
|
||||||
|
button = disnake.ui.Button(style=style, label=player_name)
|
||||||
|
button.callback = partial(choose_player, self, button)
|
||||||
|
button._view = self
|
||||||
|
self.add_item(button)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
config = Config.load()
|
config = Config.load()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import pickle
|
import pickle
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import ClassVar, Iterable, Generator
|
from typing import ClassVar, Iterable, Generator
|
||||||
|
|
||||||
|
@ -62,13 +61,15 @@ class Player:
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RoundVote:
|
class RoundVote:
|
||||||
player1: Player
|
player1: Player | None = None
|
||||||
player2: Player | None = None
|
player2: Player | None = None
|
||||||
vote: Vote | None = None
|
vote: Vote | None = None
|
||||||
timestamp: datetime | None = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def players(self) -> Iterable[Player]:
|
def players(self) -> Iterable[Player]:
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
{% for player in game.players.values() %}
|
{% for player in game.players.values() %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ player.name }}</td>
|
<td>{{ player.name }}</td>
|
||||||
<td>{{ player.score }}</td>
|
<td>{{ player.score }}{% if player.score <= 0 %} ☠️ {% elif player.score >= 9 %} 9️⃣ {% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<li>
|
<li>
|
||||||
<b>État :</b>
|
<b>État :</b>
|
||||||
{% if game.state.value == 0 %}
|
{% if game.state.value == 0 %}
|
||||||
<span style="color: yellow;">En préparation ...</span>
|
<span style="color: orange;">En préparation ...</span>
|
||||||
{% elif game.state.value == 1 %}
|
{% elif game.state.value == 1 %}
|
||||||
<span style="color: red;">Votes en cours ...</span>
|
<span style="color: red;">Votes en cours ...</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
<h2>Récapitulatif par tour</h2>
|
<h2>Récapitulatif par tour</h2>
|
||||||
|
|
||||||
{% for round in game.rounds %}
|
{% for round in game.rounds if admin or game.state.value > 0 or round.round < game.rounds|length %}
|
||||||
<h3>Tour n°{{ round.round }}</h3>
|
<h3>Tour n°{{ round.round }}</h3>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -74,9 +74,9 @@
|
||||||
{% if loop.index0 == 0 %}
|
{% if loop.index0 == 0 %}
|
||||||
<td rowspan="2">{{ room.room.value }}</td>
|
<td rowspan="2">{{ room.room.value }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>{{ vote.player1.name }}{% if vote.player2 %}, {{ vote.player2.name }}{% endif %}</td>
|
<td>{{ vote.player1.name|default('<em>personne</em>')|safe }}{% if vote.player2 %}, {{ vote.player2.name }}{% endif %}</td>
|
||||||
{% if round.round != game.rounds|length or game.state.value == 2 or admin %}
|
{% if round.round != game.rounds|length or game.state.value == 2 or admin %}
|
||||||
<td>{{ vote.vote.value|default('Pas de vote') }}</td>
|
<td>{{ vote.vote.value|default('<em>Pas de vote</em>')|safe }}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td><em>Vote en cours ...</em></td>
|
<td><em>Vote en cours ...</em></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in New Issue