diff --git a/tfjm-discord-bot.py b/tfjm-discord-bot.py index 9b68bc7..a001346 100644 --- a/tfjm-discord-bot.py +++ b/tfjm-discord-bot.py @@ -1,8 +1,10 @@ #!/bin/python - +import enum import os import sys -from typing import List +import traceback +from time import sleep +from typing import List, Dict import discord from discord.ext import commands @@ -25,6 +27,9 @@ GUILD = "690934836696973404" ORGA_ROLE = "Orga" CAPTAIN_ROLE = "Capitaine" +TIRAGE_ORDER = 0 +PASSAGE_ORDER = 1 + class TfjmError(Exception): def __init__(self, msg): @@ -35,22 +40,105 @@ class TfjmError(Exception): class Team: - def __init__(self, name): + def __init__(self, ctx, name): self.name = name + self.role = get(ctx.guild.roles, name=name) + self.tirage_order = None + self.passage_order = None class Tirage: - def __init__(self, *teams): + def __init__(self, ctx, channel, teams): assert len(teams) in (3, 4) - self.teams = {team: Team(team) for team in teams} + self.channel = channel + self.teams = {team: Team(ctx, team) for team in teams} + self.phase = OrderPhase(self) + + def team_for(self, author): + for team in self.teams: + if get(author.roles, name=team): + return self.teams[team] + + # Should theoretically not happen + raise TfjmError( + "Tu n'es pas dans une des équipes qui font le tirage, " + "merci de ne pas intervenir." + ) + + async def dice(self, ctx, author, dice): + await self.phase.dice(ctx, author, dice) + await self.update_phase(ctx) + + async def update_phase(self, ctx): + if self.phase.finished(): + self.phase = await self.phase.next(ctx) + if self.phase is None: + await ctx.send("Le tirage est fini ! Bonne chance à tous pour la suite !") + del tirages[self.channel] + + +class Phase: + NEXT = None + + def __init__(self, tirage): + self.tirage = tirage + + async def fais_pas_chier(self, ctx): + await ctx.send( + "Merci d'envoyer seulement les commandes nécessaires et suffisantes." + ) + + def team_for(self, author): + return self.tirage.team_for(author) + + @property + def teams(self): + return self.tirage.teams + + async def dice(self, ctx: Context, author, dice): + await self.fais_pas_chier(ctx) + + async def choose_problem(self, ctx: Context, author, problem): + await self.fais_pas_chier(ctx) + + async def accept(self, ctx: Context, author, yes): + await self.fais_pas_chier(ctx) + + def finished(self) -> bool: + return NotImplemented + + async def next(self, ctx: Context) -> "Phase": + return self.NEXT(self.tirage) + + +class OrderPhase(Phase): + async def dice(self, ctx, author, dice): + team = self.team_for(author) + + if team.tirage_order is None: + team.tirage_order = dice + print(f"Team {team.name} has rolled {dice}") + else: + await ctx.send(f"{author.mention}: merci de ne lancer qu'un dé.") + + def finished(self) -> bool: + return all(team.tirage_order is not None for team in self.teams.values()) + + async def next(self, ctx) -> "Phase": + orders = [team.tirage_order for team in self.teams.values()] + # Check that order is unique + if len(set(orders)) == len(orders): + return self.NEXT + else: + await ctx.send("crotte.") bot = commands.Bot( "!", help_command=commands.DefaultHelpCommand(no_category="Commandes") ) -draws = {} +tirages: Dict[int, Tirage] = {} @bot.command( @@ -63,7 +151,7 @@ async def start_draw(ctx: Context, *teams): guild: discord.Guild = ctx.guild channel = ctx.channel.id - if channel in draws: + if channel in tirages: raise TfjmError("Il y a déjà un tirage en cours sur cette Channel.") if len(teams) not in (3, 4): @@ -83,16 +171,20 @@ async def start_draw(ctx: Context, *teams): "Pour plus de détails sur le déroulement du tirgae au sort, le règlement " "est accessible sur https://tfjm.org/reglement." ) + sleep(0.5) # The bot is more human if it doesn't type at the speed of light await ctx.send( "Nous allons d'abord tirer au sort l'ordre de tirage des problèmes, " "puis l'ordre de passage lors du tour." ) + sleep(0.5) await ctx.send( f"Les {captain.mention}s, vous pouvez désormais lancer un dé 100 " "comme ceci `!dice 100`. " "L'ordre des tirages suivants sera l'ordre croissant des lancers. " ) + tirages[channel] = Tirage(ctx, channel, teams) + @bot.event async def on_ready(): @@ -112,6 +204,14 @@ async def dice(ctx: Context, n: int): dice = random.randint(1, n) await ctx.send(f"Le dé à {n} faces s'est arrêté sur... **{dice}**") + # Here we seed the result to Tirage if needed + channel = ctx.channel.id + if n == 100 and channel in tirages: + # If it is a captain + author: discord.Member = ctx.author + if get(author.roles, name=CAPTAIN_ROLE) is not None: + await tirages[channel].dice(ctx, author, dice) + @bot.command( name="choose", @@ -139,11 +239,12 @@ async def random_problem(ctx: Context): @bot.event async def on_command_error(ctx: Context, error, *args, **kwargs): if isinstance(error, commands.CommandInvokeError): - msg = str(error.original) + msg = str(error.original) or str(error) + traceback.print_tb(error.original.__traceback__, file=sys.stderr) else: msg = str(error) - print(repr(error), file=sys.stderr) + print(repr(error), dir(error), file=sys.stderr) await ctx.send(msg)