battle4suisse/bot.py

133 lines
3.9 KiB
Python
Executable File

#!/usr/bin/env python3
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",
"TH": "Thurgovie",
"TI": "Tessin",
"UR": "Uri",
"VD": "Vaud",
"VS": "Valais",
"ZG": "Zoug",
"ZH": "Zurich",
}
CodeCanton = Literal["AG", "AI", "AR", "BE", "BL", "BS", "FR", "GE", "GL", "GR", "JU", "LU", "NE",
"NW", "OW", "SG", "SH", "SO", "SZ", "TH", "TI", "UR", "VD", "VS", "ZG", "ZH"]
Couleur = Literal["rouge", "vert"]
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_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': {'rouge': [], 'vert': []}, 'cantons': {code_canton: {'capture': None, 'verrouille': False} for code_canton in CANTONS.keys()}}
with DATA_FILE.open('w') as data_file:
json.dump(data, data_file, indent=4)
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']
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()
async def carte(ctx: commands.Context):
with open('map.png', 'rb') as f:
await ctx.send(file=discord.File(f, filename="battle4suisse.png"), ephemeral=True)
@bot.command()
async def capture(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("Vous n'appartez à aucune équipe. Merci de faire `$equipe [rouge|vert]`.")
data['cantons'][canton]['capture'] = couleur
with DATA_FILE.open('w') as data_file:
json.dump(data, data_file, indent=4)
generer_carte()
return await carte(ctx)
@capture.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()
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=4)
generer_carte()
return await carte(ctx)
@bot.command()
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=4)
await ctx.send(f"Équipe {couleur} rejointe")
@equipe.error
async def equipe_error(ctx, error):
await ctx.send(str(error))
bot.run(DISCORD_TOKEN)