Files
cambot/run.py
2022-03-31 19:44:24 +02:00

222 lines
7.4 KiB
Python
Executable File

import sys
import discord
import hashlib
import re
import asyncio
import random
from datetime import datetime
import cambot.codenames as codenames
import cambot.wordle as wordle
import cambot.ephemeris as ephemeris
from cambot.emojis import *
from cambot.settings import *
bot = discord.Client()
codenames_games = {}
wordle_games = {}
# Startup
@bot.event
async def on_ready():
print(f"Connecté, nom {bot.user.name}, id {bot.user.id}")
for channel_id in CODENAMES_CHANNEL_IDS:
channel = bot.get_channel(channel_id)
codenames_game = codenames.Game(channel)
codenames_games[channel_id] = codenames_game
print(f"Écoute pour Codenames sur {channel.guild} > {channel.name}")
for channel_id in WORDLE_CHANNEL_IDS:
channel = bot.get_channel(channel_id)
wordle_game = wordle.Game(channel)
wordle_games[channel_id] = wordle_game
print(f"Écoute pour Wordle sur {channel.guild} > {channel.name}")
current_date = None
while True:
await asyncio.sleep(HEARTBEAT)
now = datetime.now()
if now.date() != current_date: # the bot was just started, OR it's a new day
events_done = [event[1] < now.time() for event in EVENTS] # mark events in the past as done
current_date = now.date()
for idx, event in enumerate(EVENTS):
if event[1] <= now.time() and not events_done[idx]:
events_done[idx] = True
if event[0] == EPHEMERIS:
embed = ephemeris.digest()
for channel_id in EPHEMERIS_CHANNEL_IDS:
await bot.get_channel(channel_id).send(embed=embed)
elif event[0] == WORDLE:
for wordle_game in wordle_games.values():
await wordle_game.reset()
# Receiving a message
@bot.event
async def on_message(message):
# Ignore own messages
if message.author == bot.user:
return
content = message.content.strip()
content_lowercase = content.lower()
# Private messages
if isinstance(message.channel, discord.channel.DMChannel):
games_entered = [codenames_game for codenames_game in codenames_games.values() if codenames_game.get_player(message.author)]
if content_lowercase.startswith("say ") and message.author.name == "Biganon" and message.author.discriminator == "0001":
arguments = content[4:].split(" ")
channel_id = int(arguments[0])
to_say = " ".join(arguments[1:])
await bot.get_channel(channel_id).send(to_say)
if content_lowercase == "target" and message.author.name == "Biganon" and message.author.discriminator == "0001":
output = ""
for wordle_game in wordle_games.values():
output += f"{wordle_game.channel.guild} > {wordle_game.channel.name} : {wordle_game.target}\n"
await message.author.send(output)
if len(games_entered) == 1:
await codenames.process_whisper(games_entered[0], message)
elif len(games_entered) > 1:
await message.author.send(f"Tu es inscrit dans plusieurs parties en même temps, je ne peux pas travailler dans ces conditions.")
else:
pass
return
# Help
if re.search(r"^!(aide|help|commandes)$", content_lowercase):
await print_help(message.channel)
# Judge something
if regex := re.search(r"^!juger (.+)$", content_lowercase):
subject = regex.group(1).strip()
score = int(hashlib.md5(bytes(subject.lower(), "utf-8")).hexdigest(), 16) % 2
opinion = ("c'est hyper bien", "c'est tellement pas OK")[score]
output = '{}, {}'.format(subject, opinion)
await message.channel.send(output)
# Dice
if regex := re.search(r"^!(?P<number>\d+)?d[eé]s?(?P<maximum>\d+)?$", content_lowercase):
thrower = message.author.display_name
maximum = 6
try:
maximum = int(regex.group("maximum"))
except (TypeError, ValueError):
pass
number = 1
try:
number = int(regex.group("number"))
except (TypeError, ValueError):
pass
results = []
for n in range(number):
result = random.randint(1, maximum)
results.append(result)
output = f"Résultat du lancer de {thrower} : **{sum(results)}**"
if len(results) > 1:
output += f" ({', '.join(map(str, results))})"
await message.channel.send(output)
# Codenames commands
if message.channel.id in codenames_games.keys():
game = codenames_games[message.channel.id]
if re.search(r"^!rouges?$", content_lowercase):
await codenames.maybe_join(game, message, codenames.Teams.RED)
elif re.search(r"^!bleus?$", content_lowercase):
await codenames.maybe_join(game, message, codenames.Teams.BLUE)
elif re.search(r"^!neutres?$", content_lowercase):
await codenames.maybe_join(game, message, codenames.Teams.NEUTRAL)
elif re.search(r"^!r[oô]les?$", content_lowercase):
await codenames.maybe_change_role(game, message)
elif re.search(r"^![eé]quipes?$", content_lowercase):
await codenames.print_teams(game)
elif re.search(r"^!config(uration)?s?$", content_lowercase):
await codenames.print_configurations(game)
elif re.search(r"^!(partir|quitter)$", content_lowercase):
await codenames.maybe_leave(game, message)
elif re.search(r"^!(jouer|play|start)$", content_lowercase):
await codenames.maybe_start(game)
elif regex := re.search(r"^!deviner (.+)$", content_lowercase):
await codenames.maybe_guess(game, message, regex.group(1))
# Wordle
if message.channel.id in wordle_games.keys():
await wordle_games[message.channel.id].parse(message)
# Help
async def print_help(channel):
output = """__Commandes de CamBot__
**Divers**
!juger `truc` : demander à Camille/CamBot de juger `truc`
!XdésY : lancer X dé(s) à Y faces. Le "s" de "dés" est optionnel. Si omis, X vaut 1 et Y vaut 6
**Codenames**
!rouge : rejoindre l'équipe rouge
!bleu : rejoindre l'équipe bleue
!neutre : rejoindre l'équipe neutre
!role : changer de rôle dans son équipe
!equipes : afficher la composition des équipes
!configurations : afficher les configurations de jeu possibles
!partir : quitter une équipe
!jouer : lancer la partie
!deviner `mot` : deviner le mot `mot`
**Divers**
!aide : afficher ce message
"""
await channel.send(output)
# Let unprivileged users pin messages
async def reaction_changed(payload):
emoji = payload.emoji
if not emoji.is_unicode_emoji():
return
if(len(emoji.name) != 1): # flags, Fitzpatrick skin tone, variation selectors...
return
if emoji.name != PUSHPIN:
return
event_type = payload.event_type
message = await bot.get_channel(payload.channel_id).fetch_message(payload.message_id)
if event_type == "REACTION_ADD":
await message.pin()
elif event_type == "REACTION_REMOVE":
await message.unpin()
@bot.event
async def on_raw_reaction_add(payload):
await reaction_changed(payload)
@bot.event
async def on_raw_reaction_remove(payload):
await reaction_changed(payload)
if __name__ == "__main__":
bot.run(DISCORD_TOKEN)