247 lines
9.7 KiB
Python
247 lines
9.7 KiB
Python
from discord.ext import tasks
|
|
from datetime import datetime, timedelta, timezone
|
|
from dotenv import load_dotenv
|
|
import discord
|
|
import os
|
|
import asyncio
|
|
import random
|
|
import re
|
|
import json
|
|
import time
|
|
|
|
intents = discord.Intents.default()
|
|
intents.members = True
|
|
intents.presences = True
|
|
intents.guilds = True
|
|
intents.messages = True
|
|
intents.message_content = True
|
|
client = discord.Client(intents=intents)
|
|
load_dotenv()
|
|
token = os.getenv('DISCORD_TOKEN', "NO_TOKEN")
|
|
|
|
client.riddles = []
|
|
client.answers = []
|
|
client.rhyme_keys = {}
|
|
client.rhyme_strings = {}
|
|
client.cooldown = {}
|
|
client.ongoing_riddles = {}
|
|
|
|
def load_riddles():
|
|
with open('riddles.txt', 'r', encoding='utf-8') as r_file:
|
|
client.riddles = r_file.read().split('\n\n')
|
|
with open('answers.txt', 'r', encoding='utf-8') as a_file:
|
|
client.answers = [line.strip() for line in a_file.readlines()]
|
|
print('Loaded {0} riddles'.format(len(client.riddles)))
|
|
|
|
def load_rhymes():
|
|
with open('rhymes.txt', 'r', encoding='utf-8') as f:
|
|
data = f.read()
|
|
|
|
keys_start = data.index('[KEYS]') + len('[KEYS]\n')
|
|
keys_end = data.index('[RHYMES]')
|
|
keys_data = data[keys_start:keys_end].split('\n')
|
|
keys = {}
|
|
for key_data in keys_data:
|
|
if key_data:
|
|
k, v = key_data.split(":")
|
|
keys[k] = v.split(',')
|
|
|
|
rhymes_start = data.index('[RHYMES]') + len('[RHYMES]\n')
|
|
rhymes_data = data[rhymes_start:].split('\n')
|
|
rhymes = {}
|
|
for rhyme_data in rhymes_data:
|
|
if rhyme_data:
|
|
k, v = rhyme_data.split(":")
|
|
rhymes[k] = v.split(',')
|
|
|
|
client.rhyme_keys = keys
|
|
client.rhyme_strings = rhymes
|
|
|
|
def new_riddle(channel, index):
|
|
current_riddle = dict(index=index, nbClues=-1, riddle=client.riddles[index].strip(), answer=client.answers[index])
|
|
client.ongoing_riddles[channel] = current_riddle
|
|
return format_message(current_riddle)
|
|
|
|
def finish_riddle(channel):
|
|
del client.ongoing_riddles[channel]
|
|
|
|
def clue_string(answer, nbClues):
|
|
finalString = "_"
|
|
for i in range(len(answer) - 1):
|
|
finalString += " _"
|
|
random.seed(hash(answer))
|
|
nbRevealed = 0
|
|
for i in range(nbClues):
|
|
|
|
id = random.randint(0, len(answer) - 1)
|
|
while finalString[id * 2] != '_':
|
|
id = random.randint(0, len(answer) - 1)
|
|
|
|
nbRevealed += 1
|
|
finalString = finalString[:id * 2] + answer[id] + finalString[id * 2 + 1:]
|
|
|
|
if nbRevealed == len(answer):
|
|
return finalString
|
|
return finalString
|
|
|
|
def format_message(current_riddle):
|
|
nbClues = current_riddle['nbClues']
|
|
answer = current_riddle['answer']
|
|
|
|
formatted_riddle = "> " + current_riddle['riddle'].replace("\n", "\n> ")
|
|
formatted_riddle = formatted_riddle.replace("\r", "")
|
|
|
|
clue = ""
|
|
if nbClues > -1:
|
|
if nbClues >= len(answer):
|
|
clue = clue + "\nNon trouvée, la solution était : `{0}`".format(answer)
|
|
else:
|
|
clue = clue + "\nIndice : `{0}`".format(clue_string(answer, nbClues))
|
|
|
|
if 'solver' in current_riddle:
|
|
clue = clue + "\n{0} a trouvé la solution, qui était : `{1}`".format(current_riddle['solver'].mention, answer)
|
|
|
|
if clue:
|
|
return "Énigme {0}:\n{1}\n{2}".format(current_riddle['index'] + 1, formatted_riddle, clue)
|
|
else:
|
|
return "Énigme {0}:\n{1}".format(current_riddle['index'] + 1, formatted_riddle)
|
|
|
|
def get_last_word(ch:str)->str:
|
|
truncated = ch
|
|
while True:
|
|
if len(truncated) < 2 or truncated[-1].isnumeric():
|
|
return ''
|
|
if truncated[-1].isalpha() and truncated[-2].isalpha():
|
|
break
|
|
truncated = truncated[:-1]
|
|
return truncated
|
|
|
|
def poil_auquel(ch:str)->str:
|
|
for key in client.rhyme_keys:
|
|
if ch.endswith(tuple(client.rhyme_keys[key])):
|
|
return random.choice(client.rhyme_strings[key])
|
|
return ''
|
|
|
|
async def get_channel_name(channel)->str:
|
|
if isinstance(channel, discord.DMChannel):
|
|
dm_channel = await client.fetch_channel(channel.id)
|
|
return '[DM={0}]'.format(dm_channel.recipient.name)
|
|
else:
|
|
return '[Server={0}] => [Channel={1}]'.format(channel.guild.name, channel.name)
|
|
|
|
|
|
@client.event
|
|
async def on_ready():
|
|
load_riddles()
|
|
load_rhymes()
|
|
print('Logged in as {0.user}'.format(client))
|
|
|
|
@client.event
|
|
async def on_message(message):
|
|
# don't answer to self
|
|
if message.author == client.user and message.channel in client.ongoing_riddles:
|
|
current_riddle = client.ongoing_riddles[message.channel]
|
|
if not ('message' in current_riddle):
|
|
current_riddle['message'] = message
|
|
return
|
|
|
|
if isinstance(message.channel, discord.DMChannel) or isinstance(message.channel, discord.TextChannel) or isinstance(message.channel, discord.Thread):
|
|
message_content = message.content.lower()
|
|
|
|
# command fouras
|
|
fouras_match = re.match(r"^fouras\s+(\d+)$", message_content)
|
|
if fouras_match:
|
|
index = int(fouras_match.group(1)) - 1
|
|
if index >= 0 and index < len(client.riddles):
|
|
if random.random() <= 0.03:
|
|
await message.channel.send("Non")
|
|
else:
|
|
await message.channel.send(new_riddle(message.channel, index))
|
|
else:
|
|
await message.channel.send("Numéro d'énigme invalide, merci de saisir un numéro entre 1 et {0}".format(len(client.riddles)))
|
|
return
|
|
if message_content == 'fouras':
|
|
if random.random() <= 0.03:
|
|
await message.channel.send("Non")
|
|
elif len(client.riddles) > 0:
|
|
index = random.randint(0, len(client.riddles) - 1)
|
|
await message.channel.send(new_riddle(message.channel, index))
|
|
return
|
|
|
|
# command reload
|
|
if message_content == 'reload_riddles':
|
|
load_riddles()
|
|
await message.channel.send('Loaded {0} riddles'.format(len(client.riddles)))
|
|
return
|
|
|
|
if message_content == 'about fouras':
|
|
author_user = await client.fetch_user(151626081458192384)
|
|
await message.channel.send(f"Ce bot a été développé par {author_user.mention}\nCode Source : https://gitlab.epicsparrow.com/Anselme/perefouras\nAjouter ce bot à votre serveur : https://discord.com/api/oauth2/authorize?client_id=1110208055171367014&permissions=274877975552&scope=bot")
|
|
return
|
|
|
|
if message_content == 'debug fouras':
|
|
dump = {}
|
|
cooldowns = {}
|
|
for key, value in client.cooldown.items():
|
|
channel_name = await get_channel_name(key)
|
|
cooldowns[channel_name] = value - time.time()
|
|
dump['poil_au_cooldown'] = cooldowns
|
|
for key, value in client.ongoing_riddles.items():
|
|
dump_channel = value
|
|
dump_channel.pop("message", None)
|
|
dump_channel['answer'] = '||{0}||'.format(dump_channel['answer'])
|
|
channel_name = await get_channel_name(key)
|
|
dump[channel_name] = dump_channel
|
|
await message.author.send(json.dumps(dump, ensure_ascii=False, indent=4))
|
|
return
|
|
|
|
# if current channel has ongoing riddle
|
|
if message.channel in client.ongoing_riddles:
|
|
current_riddle = client.ongoing_riddles[message.channel]
|
|
|
|
if 'message' in current_riddle:
|
|
answer = current_riddle["answer"]
|
|
if answer.lower() in message_content:
|
|
current_riddle["solver"] = message.author
|
|
|
|
await message.channel.send(f"Bravo {message.author.mention} ! La réponse était bien `{answer}`.")
|
|
await current_riddle['message'].edit(content=format_message(current_riddle))
|
|
finish_riddle(message.channel)
|
|
return
|
|
|
|
if message_content == 'repete' or message_content == 'répète' or message_content == 'repeat':
|
|
current_riddle.pop('message')
|
|
await message.channel.send(format_message(current_riddle))
|
|
return
|
|
|
|
# Commande /clue : révèle une lettre au hasard de la réponse attendue
|
|
if message_content == 'indice' or message_content == 'aide' or message_content == 'connard de fouras':
|
|
nbClues = current_riddle["nbClues"] + 1
|
|
current_riddle["nbClues"] = nbClues
|
|
if nbClues >= len(answer):
|
|
reply = "Perdu ! La réponse était : `{0}`".format(answer)
|
|
await message.channel.send(reply)
|
|
# else:
|
|
# reply = "Indice : `{0}`".format(clue_string(answer, nbClues))
|
|
await current_riddle['message'].edit(content=format_message(current_riddle))
|
|
if nbClues >= len(answer):
|
|
finish_riddle(message.channel)
|
|
return
|
|
|
|
last_word = get_last_word(message_content)
|
|
if last_word:
|
|
poil = poil_auquel(last_word)
|
|
cooldown = 0
|
|
if message.channel in client.cooldown:
|
|
cooldown = client.cooldown[message.channel]
|
|
if poil and time.time() - cooldown > 0:
|
|
wait_time = random.randint(0, 900)
|
|
if bool(random.getrandbits(1)):
|
|
wait_time = random.randint(900, 10800)
|
|
client.cooldown[message.channel] = time.time() + wait_time
|
|
await message.channel.send(poil)
|
|
return
|
|
|
|
# Initialise le client
|
|
client.run(token)
|