510 lines
22 KiB
Python
Executable File
510 lines
22 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from collections import namedtuple
|
|
import copy
|
|
from datetime import datetime, timedelta
|
|
from functools import partial
|
|
import json
|
|
from pathlib import Path
|
|
import random
|
|
from typing import Literal
|
|
from xml.dom import minidom
|
|
|
|
import cairosvg
|
|
import discord
|
|
from discord.ext import commands
|
|
|
|
from config import *
|
|
|
|
|
|
CANTONS = {
|
|
"AG": "Argovie",
|
|
"AI": "Appenzell Rhodes-Intérieures",
|
|
"AR": "Appenzell Rhodes-Extérieures",
|
|
"BE": "Berne",
|
|
"BL": "Bâle-Campagne",
|
|
"BS": "Bâle-Ville",
|
|
"FR": "Fribourg",
|
|
"GE": "Genève",
|
|
"GL": "Glaris",
|
|
"GR": "Grisons",
|
|
"JU": "Jura",
|
|
"LU": "Lucerne",
|
|
"NE": "Neuchâtel",
|
|
"NW": "Nidwald",
|
|
"OW": "Obwald",
|
|
"SG": "Saint-Gall",
|
|
"SH": "Schaffhouse",
|
|
"SO": "Soleure",
|
|
"SZ": "Schwytz",
|
|
"TG": "Thurgovie",
|
|
"TI": "Tessin",
|
|
"UR": "Uri",
|
|
"VD": "Vaud",
|
|
"VS": "Valais",
|
|
"ZG": "Zoug",
|
|
"ZH": "Zurich",
|
|
}
|
|
|
|
EQUIPES = ["rouge", "vert"]
|
|
|
|
CodeCanton = Literal["AG", "AI", "AR", "BE", "BL", "BS", "FR", "GE", "GL", "GR", "JU", "LU", "NE",
|
|
"NW", "OW", "SG", "SH", "SO", "SZ", "TG", "TI", "UR", "VD", "VS", "ZG", "ZH"]
|
|
Couleur = Literal["rouge", "vert"]
|
|
|
|
|
|
intents = discord.Intents.default()
|
|
intents.message_content = True
|
|
|
|
PREFIX = '!'
|
|
bot = commands.Bot(command_prefix=PREFIX, intents=intents)
|
|
|
|
DATA_FILE = Path(__file__).parent / "data.json"
|
|
if DATA_FILE.exists():
|
|
with DATA_FILE.open() as data_file:
|
|
data = json.load(data_file)
|
|
else:
|
|
data = {
|
|
'equipes': {equipe: [] for equipe in EQUIPES},
|
|
'cantons': {code_canton: {'capture': None, 'verrouille': False} for code_canton in CANTONS.keys()},
|
|
'defis': {
|
|
'mains': {equipe: [] for equipe in EQUIPES},
|
|
'bonus': {equipe: 0 for equipe in EQUIPES},
|
|
'tires_capture': [],
|
|
'tires_vol': [],
|
|
}
|
|
}
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
|
|
DEFIS_FILE = Path(__file__).parent / "defis.json"
|
|
with DEFIS_FILE.open() as defis_file:
|
|
DEFIS = json.load(defis_file)
|
|
|
|
|
|
def generer_carte():
|
|
doc = minidom.parse("map_blank.svg")
|
|
for code_canton, data_canton in data['cantons'].items():
|
|
if data_canton['capture']:
|
|
path = next(e for e in doc.getElementsByTagName('path') if e.getAttribute('id') == code_canton)
|
|
couleur = data_canton['capture']
|
|
if data_canton['verrouille']:
|
|
path.setAttribute('fill', f"url(#verrouille-{couleur})")
|
|
else:
|
|
path.setAttribute('class', f"capture-{couleur}")
|
|
with open('map.svg', 'w') as f:
|
|
doc.writexml(f)
|
|
cairosvg.svg2png(url='map.svg', write_to='map.png')
|
|
|
|
|
|
@bot.command(brief="Affche la carte des cantons capturés.")
|
|
async def carte(ctx: commands.Context):
|
|
rouges = list(canton_code for canton_code, canton in data['cantons'].items()
|
|
if canton['capture'] == "rouge")
|
|
rouges_verrouilles = list(canton_code for canton_code, canton in data['cantons'].items()
|
|
if canton['capture'] == "rouge" and canton['verrouille'])
|
|
noms_rouges = ", ".join(code_canton + (":lock:" if code_canton in rouges_verrouilles else "") for code_canton in rouges)
|
|
verts = list(canton_code for canton_code, canton in data['cantons'].items()
|
|
if canton['capture'] == "vert")
|
|
verts_verrouilles = list(canton_code for canton_code, canton in data['cantons'].items()
|
|
if canton['capture'] == "vert" and canton['verrouille'])
|
|
noms_verts = ", ".join(code_canton + (":lock:" if code_canton in verts_verrouilles else "") for code_canton in verts)
|
|
libres = list(canton_code for canton_code, canton in data['cantons'].items()
|
|
if canton['capture'] is None)
|
|
message = f""":red_circle: Équipe rouge : **{len(rouges)} canton{"s" if len(rouges) > 1 else ""}** (dont **{len(rouges_verrouilles)} verrouillé{"s" if len(rouges_verrouilles) > 1 else ""}**) : {noms_rouges}
|
|
:green_circle: Équipe verte : **{len(verts)} canton{"s" if len(verts) > 1 else ""}** (dont **{len(verts_verrouilles)} verrouillé{"s" if len(verts_verrouilles) > 1 else ""}**) : {noms_verts}
|
|
:white_circle: **{len(libres)} canton{"s" if len(libres) > 1 else ""}** libre{"s" if len(libres) > 1 else ""} : {", ".join(libres)}"""
|
|
generer_carte()
|
|
with open('map.png', 'rb') as f:
|
|
await ctx.send(message, file=discord.File(f, filename="battle4suisse.png"))
|
|
|
|
|
|
@bot.command(brief=f"Capture un canton pour son équipe : {PREFIX}capturer CODE_CANTON [EQUIPE]")
|
|
async def capturer(ctx: commands.Context, canton: CodeCanton, *, couleur: Couleur | None = None):
|
|
if couleur is None:
|
|
author_id = ctx.author.id
|
|
for couleur, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
data['cantons'][canton]['capture'] = couleur
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.send(f"@everyone L'équipe {couleur} a capturé le canton de **{CANTONS[canton]}** !")
|
|
return await carte(ctx)
|
|
|
|
|
|
@capturer.error
|
|
async def capture_error(ctx, error):
|
|
if isinstance(error, commands.BadLiteralArgument):
|
|
await ctx.send(f"Canton inconnu : {error.argument}, valeurs possibles : {", ".join(error.literals)}")
|
|
else:
|
|
await ctx.send(str(error))
|
|
|
|
|
|
@bot.command(brief=f"Verrouille un canton sur la carte pour son équipe : {PREFIX}verrouiller CODE_CANTON [EQUIPE]")
|
|
async def verrouiller(ctx: commands.Context, canton: CodeCanton, *, couleur: Couleur | None = None):
|
|
if couleur is None:
|
|
author_id = ctx.author.id
|
|
for couleur, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
data['cantons'][canton]['capture'] = couleur
|
|
data['cantons'][canton]['verrouille'] = True
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
generer_carte()
|
|
await ctx.send(f"@everyone L'équipe {couleur} a capturé le canton de **{CANTONS[canton]}** !")
|
|
return await carte(ctx)
|
|
|
|
|
|
@bot.command(brief=f"Réinitialise l'état de capture d'un canton : {PREFIX}reset CODE_CANTON")
|
|
async def reset(ctx: commands.Context, canton: CodeCanton):
|
|
data['cantons'][canton]['capture'] = None
|
|
data['cantons'][canton]['verrouille'] = False
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
generer_carte()
|
|
return await carte(ctx)
|
|
|
|
|
|
@bot.command(brief=f"Rejoindre une équipe : {PREFIX}equipe EQUIPE")
|
|
async def equipe(ctx: commands.Context, couleur: Couleur):
|
|
author_id = ctx.author.id
|
|
for membres_equipe in data['equipes'].values():
|
|
if author_id in membres_equipe:
|
|
membres_equipe.remove(author_id)
|
|
data['equipes'][couleur].append(author_id)
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.send(f"Équipe {couleur} rejointe")
|
|
|
|
|
|
@bot.command(brief=f"Affiche la liste des noms des défis : {PREFIX}defis [capture | vol]")
|
|
async def defis(ctx: commands.Context, *, type_defi: Literal['capture', 'vol'] = "capture"):
|
|
await ctx.send(f"Liste des défis de {type_defi} :\n" + "\n".join(f"* {defi['id']} : {defi['nom']}" for defi in DEFIS[type_defi]))
|
|
|
|
|
|
@bot.command(brief=f"Affiche la description des défis")
|
|
async def description(ctx: commands.Context, type_defi: Literal['capture', 'vol'] = "capture", id_defi: int | None = None):
|
|
defis = DEFIS[type_defi]
|
|
embeds = []
|
|
if id_defi is not None:
|
|
embed = discord.Embed(title=f"Description du défi {id_defi}", colour=discord.Colour.gold())
|
|
try:
|
|
defi = next(defi for defi in defis if defi['id'] == id_defi)
|
|
except StopIteration:
|
|
raise commands.BadArgument(f"Le défi de {type_defi} n°{id_defi} n'existe pas.")
|
|
embed.add_field(name=f"{defi['nom']} {defi['bonus'] * ":star:"}", value=defi['description'], inline=False)
|
|
embeds.append(embed)
|
|
else:
|
|
for page in range((len(defis) - 1) // 25 + 1):
|
|
defis_page = defis[page * 25:(page + 1) * 25]
|
|
embed = discord.Embed(title=f"Description des défis", colour=discord.Colour.gold())
|
|
embed.set_footer(text=f"Page {page + 1}/{(len(defis) - 1) // 25 + 1}")
|
|
for defi in defis_page:
|
|
embed.add_field(name=f"{defi['nom']} {defi['bonus'] * ":star:"} (n°{defi['id']})", value=defi['description'], inline=False)
|
|
embeds.append(embed)
|
|
await ctx.send(embeds=embeds)
|
|
|
|
|
|
@bot.command()
|
|
async def tirage(ctx: commands.Context, nb_defis: int = 5):
|
|
if any(data['defis']['mains'][equipe] for equipe in EQUIPES):
|
|
raise commands.BadArgument("Les mains sont déjà initialisées")
|
|
|
|
defis_libres = copy.deepcopy(DEFIS['capture'])
|
|
for equipe in EQUIPES:
|
|
for _i in range(nb_defis):
|
|
defi = random.choice(defis_libres)
|
|
defis_libres.remove(defi)
|
|
data['defis']['mains'][equipe].append(defi['id'])
|
|
data['defis']['tires_capture'].append(defi['id'])
|
|
|
|
for member_id in data['equipes'][equipe]:
|
|
await afficher_main(ctx, author_id=member_id)
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.send("Les mains de départ ont bien été tirées ! Le contenu vous a été envoyé en MP.")
|
|
|
|
|
|
@bot.command()
|
|
async def vol(ctx: commands.Context):
|
|
defi_vol = random.choice([defi for defi in DEFIS['vol'] if defi['id'] not in data['defis']['tires_vol']])
|
|
data['defis']['tires_vol'].append(defi_vol['id'])
|
|
embed = discord.Embed(title=defi_vol['nom'], description=defi_vol['description'])
|
|
embed.set_footer(text=f"Défi de compétition n°{defi_vol['id']}")
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.send("@everyone Un canton est attaqué ! L'équipe vainqueure de ce défi conservera son contrôle jusqu'à la fin du jeu :", embed=embed)
|
|
|
|
|
|
@bot.command()
|
|
async def remiser(ctx: commands.Context, type_defi: Literal['capture', 'vol'] = "capture", id_defi: int | None = None):
|
|
defis = DEFIS[type_defi]
|
|
try:
|
|
defi = next(defi for defi in defis if defi['id'] == id_defi)
|
|
except StopIteration:
|
|
raise commands.BadArgument(f"Le défi de {type_defi} n°{id_defi} n'existe pas.")
|
|
if id_defi in data['defis'][f'tires_{type_defi}']:
|
|
data['defis'][f'tires_{type_defi}'].remove(id_defi)
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.reply(f"Le défi de {type_defi} n°{id_defi} ({defi['nom']}) a été retiré de la défausse et pourra à nouveau être tiré au sort.")
|
|
else:
|
|
await ctx.reply(f"Le défi de {type_defi} n°{id_defi} ({defi['nom']}) n'était déjà pas dans la défausse.")
|
|
|
|
|
|
class MainView(discord.ui.View):
|
|
def __init__(self, ctx: commands.Context, user_id: int, defis: list[dict], timeout: float | None = 180.0):
|
|
super().__init__(timeout=timeout)
|
|
|
|
async def terminer_defi(self, id_defi: int, user_id: int, interaction: discord.Interaction):
|
|
await interaction.response.defer()
|
|
await terminer(ctx, id_defi, user_id, interaction.channel)
|
|
|
|
for id_defi in defis:
|
|
defi = next(defi for defi in DEFIS['capture'] if defi['id'] == id_defi)
|
|
button = discord.ui.Button(style=discord.ButtonStyle.success, label=f"Terminer {defi['nom']}")
|
|
button.callback = partial(terminer_defi, self, id_defi, user_id)
|
|
self.add_item(button)
|
|
|
|
|
|
|
|
@bot.command(name="main")
|
|
async def afficher_main(ctx: commands.Context, mode: Literal['public', 'prive'] = "prive", author_id: int | None = None):
|
|
author_id = author_id or ctx.author.id
|
|
for couleur, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
|
|
main = data['defis']['mains'][couleur]
|
|
nb_bonus = data['defis']['bonus'][couleur]
|
|
embeds = []
|
|
colour = discord.Color.red() if couleur == "rouge" else discord.Color.green()
|
|
for id_defi in main:
|
|
defi = next(defi for defi in DEFIS['capture'] if defi['id'] == id_defi)
|
|
embed = discord.Embed(title=f"{defi['nom']} {defi['bonus'] * ":star:"}", description=defi['description'], colour=colour)
|
|
embed.set_footer(text=f"Défi n°{defi['id']}")
|
|
embeds.append(embed)
|
|
if mode == "public":
|
|
await ctx.send(f"Défis de l'équipe **{couleur}** :", embeds=embeds)
|
|
else:
|
|
channel_dm = await bot.create_dm(namedtuple('User', 'id')(author_id))
|
|
await channel_dm.send(f"Vous disposez de **{nb_bonus} bonus {nb_bonus * ":star:"}**.\nVos défis en main :", embeds=embeds, view=MainView(ctx, author_id, main))
|
|
|
|
|
|
@bot.command()
|
|
async def terminer(ctx: commands.Context, id_defi: int, author_id: int | None = None, channel: discord.abc.Messageable | None = None):
|
|
if all(id_defi != defi['id'] for defi in DEFIS['capture']):
|
|
raise commands.BadArgument(f"Erreur : Le défi {id_defi_1} n'existe pas")
|
|
defi = next(defi for defi in DEFIS['capture'] if defi['id'] == id_defi)
|
|
author_id = author_id or ctx.author.id
|
|
for equipe, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
|
|
main = data['defis']['mains'][equipe]
|
|
if id_defi not in main:
|
|
raise commands.BadArgument(f"Le défi {id_defi} n'est pas dans votre main. Faites `{PREFIX}main` pour afficher votre main.")
|
|
|
|
nouveau_defi = random.choice([defi for defi in DEFIS['capture'] if defi['id'] not in data['defis']['tires_capture']])
|
|
main.remove(id_defi)
|
|
main.append(nouveau_defi['id'])
|
|
data['defis']['tires_capture'].append(nouveau_defi['id'])
|
|
data['defis']['bonus'][equipe] += defi['bonus']
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
|
|
channel = channel or ctx
|
|
await channel.send(f"Défi n°{id_defi} **{defi['nom']}** terminé ! Il est retiré de votre main.")
|
|
await channel.send(f"Votre équipe gagne **{defi['bonus']} bonus**. Vous en possédez désormais {data['defis']['bonus'][equipe]}.")
|
|
colour = discord.Color.red() if equipe == "rouge" else discord.Color.green()
|
|
embed = discord.Embed(title=f"{nouveau_defi['nom']} {defi['bonus'] * ":star:"}", description=nouveau_defi['description'], colour=colour)
|
|
embed.set_footer(text=f"Défi n°{nouveau_defi['id']}")
|
|
await channel.send("**Votre nouveau défi en main :**", embed=embed)
|
|
for member_id in data['equipes'][equipe]:
|
|
await afficher_main(ctx, author_id=member_id)
|
|
|
|
|
|
@bot.command()
|
|
async def bonus(ctx: commands.Context, equipe: Couleur | None = None, nouvelle_valeur: int | None = None):
|
|
if equipe is None:
|
|
author_id = ctx.author.id
|
|
for equipe, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
|
|
nb_bonus = data['defis']['bonus'][equipe]
|
|
if nouvelle_valeur is None:
|
|
if nb_bonus >= 1:
|
|
data['defis']['bonus'][equipe] -= 1
|
|
await ctx.send(f"L'équipe **{equipe}** vient d'utiliser un bonus !")
|
|
else:
|
|
await ctx.reply(f"Vous n'avez plus de bonus.", ephemeral=True)
|
|
else:
|
|
data['defis']['bonus'][equipe] = nouvelle_valeur
|
|
await ctx.send(f"L'équipe **{equipe}** a désormais **{nouvelle_valeur} bonus**, contre {nb_bonus} auparavant.")
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
|
|
|
|
@bot.command()
|
|
async def echange(ctx: commands.Context, id_defi_1: int, id_defi_2: int):
|
|
if all(id_defi_1 != defi['id'] for defi in DEFIS['capture']):
|
|
raise commands.BadArgument(f"Erreur : Le défi {id_defi_1} n'existe pas")
|
|
if all(id_defi_2 != defi['id'] for defi in DEFIS['capture']):
|
|
raise commands.BadArgument(f"Erreur : Le défi {id_defi_2} n'existe pas")
|
|
defi_1 = next(defi for defi in DEFIS['capture'] if defi['id'] == id_defi_1)
|
|
defi_2 = next(defi for defi in DEFIS['capture'] if defi['id'] == id_defi_2)
|
|
|
|
equipe_1, equipe_2 = None, None
|
|
for equipe in EQUIPES:
|
|
main = data['defis']['mains'][equipe]
|
|
if id_defi_1 in main:
|
|
equipe_1 = equipe
|
|
if id_defi_2 in main:
|
|
equipe_2 = equipe
|
|
if equipe_1 is None and equipe_2 is None:
|
|
raise commands.BadArgument("Erreur : Aucun des deux défis n'est fait par une équipe")
|
|
elif equipe_1 == equipe_2:
|
|
raise commands.BadArgument(f"Erreur : Les défis {id_defi_1} et {id_defi_2} sont tous les deux fait par la même équipe {equipe_1}")
|
|
|
|
if equipe_1 is not None:
|
|
data['defis']['mains'][equipe_1].remove(id_defi_1)
|
|
data['defis']['mains'][equipe_1].append(id_defi_2)
|
|
else:
|
|
tires_capture = data['defis']['tires_capture']
|
|
if id_defi_1 not in tires_capture:
|
|
tires_capture.append(id_defi_1)
|
|
if id_defi_2 in tires_capture:
|
|
tires_capture.remove(id_defi_2)
|
|
|
|
if equipe_2 is not None:
|
|
data['defis']['mains'][equipe_2].remove(id_defi_2)
|
|
data['defis']['mains'][equipe_2].append(id_defi_1)
|
|
else:
|
|
tires_capture = data['defis']['tires_capture']
|
|
if id_defi_1 in tires_capture:
|
|
tires_capture.remove(id_defi_1)
|
|
if id_defi_2 not in tires_capture:
|
|
tires_capture.append(id_defi_2)
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
|
|
if equipe_1 is not None and equipe_2 is not None:
|
|
await ctx.send(f"Le défi **{defi_1['nom']}** de l'équipe **{equipe_1}** et le défi **{defi_2['nom']}** de l'équipe **{equipe_2}** ont été échangés !")
|
|
else:
|
|
await ctx.send(f"Les défis **{defi_1['nom']}** et **{defi_2['nom']}** ont été échangés !")
|
|
|
|
|
|
@bot.command()
|
|
async def melanger(ctx: commands.Context, nb_defis: int = 5):
|
|
author_id = ctx.author.id
|
|
for equipe, membres_equipe in data['equipes'].items():
|
|
if author_id in membres_equipe:
|
|
break
|
|
else:
|
|
raise commands.BadArgument(f"Vous n'appartez à aucune équipe. Merci de faire `{PREFIX}equipe [{"|".join(EQUIPES)}]`.")
|
|
|
|
main = data['defis']['mains'][equipe]
|
|
|
|
for _i in range(nb_defis):
|
|
nouveau_defi = random.choice([defi for defi in DEFIS['capture'] if defi['id'] not in data['defis']['tires_capture']])
|
|
main.append(nouveau_defi['id'])
|
|
data['defis']['tires_capture'].append(nouveau_defi['id'])
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
|
|
await ctx.send(f"Main de l'équipe {equipe} mélangée !")
|
|
for member_id in data['equipes'][equipe]:
|
|
await afficher_main(ctx, author_id=member_id)
|
|
|
|
|
|
@bot.command()
|
|
async def de(ctx: commands.Context, nb_faces: int = 6):
|
|
resultat = random.randint(1, nb_faces + 1)
|
|
await ctx.reply(f":game_die: Résultat du dé à {nb_faces} faces : **{resultat}**")
|
|
|
|
|
|
@bot.command()
|
|
async def chronometre(ctx: commands.Context, minutes: int = 30, secondes: int = 0):
|
|
fin = datetime.now() + timedelta(minutes=minutes, seconds=secondes)
|
|
await ctx.send(f"Chronomètre lancé pour **{minutes:02d}:{secondes:02d}** (fin à <t:{int(fin.timestamp())}:T>)\nFin <t:{int(fin.timestamp())}:R>")
|
|
|
|
|
|
@bot.command()
|
|
async def debug(ctx: commands.Context, keys: str, *, set_value: str | None = None):
|
|
keys = keys.split('.')
|
|
parent = None
|
|
out = data
|
|
for key in keys:
|
|
if key not in out:
|
|
raise commands.BadArgument(f"Clé {key} absente du dictionnaire, valeurs possibles : {out.keys()}")
|
|
parent = out
|
|
last_key = key
|
|
out = out[key]
|
|
data_json = json.dumps(out, indent=2)
|
|
if set_value is None:
|
|
await ctx.reply(f"```json\n{data_json}\n```", ephemeral=True)
|
|
else:
|
|
new_data = json.loads(set_value)
|
|
new_data_json = json.dumps(new_data, indent=2)
|
|
parent[last_key] = new_data
|
|
await ctx.reply(f"Anciennes données :\n```json\n{data_json}\n```Nouvelles données :\n```json\n{new_data_json}\n```\nFaites `{PREFIX}save` pour sauvegarder, ou `{PREFIX}` reload pour rollback.", ephemeral=True)
|
|
|
|
|
|
@bot.command()
|
|
async def reload(ctx: commands.Context):
|
|
global data, DEFIS
|
|
with DATA_FILE.open() as data_file:
|
|
data = json.load(data_file)
|
|
with DEFIS_FILE.open() as defis_file:
|
|
DEFIS = json.load(defis_file)
|
|
await ctx.reply("Configuration rechargée.", ephemeral=True)
|
|
|
|
|
|
@bot.command()
|
|
async def save(ctx: commands.Context):
|
|
with DATA_FILE.open('w') as data_file:
|
|
json.dump(data, data_file, indent=2)
|
|
await ctx.reply("Configuration sauvegardée.", ephemeral=True)
|
|
|
|
|
|
@carte.error
|
|
@reset.error
|
|
@equipe.error
|
|
@defis.error
|
|
@description.error
|
|
@tirage.error
|
|
@vol.error
|
|
@remiser.error
|
|
@afficher_main.error
|
|
@terminer.error
|
|
@bonus.error
|
|
@echange.error
|
|
@melanger.error
|
|
@de.error
|
|
@chronometre.error
|
|
@debug.error
|
|
@reload.error
|
|
@save.error
|
|
async def on_error(ctx, error):
|
|
with DATA_FILE.open() as data_file:
|
|
data = json.load(data_file)
|
|
await ctx.send(str(error))
|
|
if not isinstance(error, commands.BadArgument):
|
|
raise error
|
|
|
|
|
|
bot.run(DISCORD_TOKEN)
|