perefouras/modules/fouras.py
2023-07-27 23:17:34 +02:00

287 lines
11 KiB
Python

from .base import BaseModule, ENCODING
import random
import re
import json
from unidecode import unidecode
import appdirs
import os
API_URL = "".join(
[
"https://discord.com/api/oauth2/authorize?",
"client_id=1110208055171367014&permissions=274877975552&scope=bot",
]
)
MAINTAINER_ID = 151626081458192384
BUG_REPORT = """
BUG REPORT from {user} (`{user_id}`) in channel {channel} (`{channel_id}`) :
Message :
> {message}
State :
```json\n{state}```
History :
```json\n{history}```
"""
ABOUT = """
Ce bot a été développé par {user}
Code Source : https://gitlab.epicsparrow.com/Anselme/perefouras
Ajouter ce bot à votre serveur : {url}
"""
SUCCESS = """
Bravo {user} ! La réponse était bien `{answer}`.
"""
INVALID_ID = """
Numéro d'énigme invalide, merci de saisir un numéro entre 1 et {len}
"""
RIDDLES_FILE = "riddles.txt"
ANSWERS_FILE = "answers.txt"
SAVE_FILE = appdirs.user_data_dir() + "/PereFouras/fouras_riddles.json"
class FourasModule(BaseModule):
async def load(self):
with open(RIDDLES_FILE, "r", encoding=ENCODING) as r_file:
self._client.riddles = r_file.read().split("\n\n")
with open(ANSWERS_FILE, "r", encoding=ENCODING) as a_file:
self._client.answers = [line.strip() for line in a_file.readlines()]
str=f"Loaded {len(self._client.riddles)} riddles"
try:
with open(SAVE_FILE, "r") as file:
config = json.load(file)
ongoing_riddles = dict()
for k, v in config.items():
channel = await self._client.fetch_channel(int(k))
channel_info = v
channel_info["message"] = await channel.fetch_message(channel_info["message"])
ongoing_riddles[channel] = channel_info
self._client.ongoing_riddles = ongoing_riddles
str = str + 'Loaded fouras save file "{0}"'.format(SAVE_FILE)
except FileNotFoundError:
str = str + 'No previous "{0}" save file found'.format(SAVE_FILE)
except json.JSONDecodeError:
str = str + '"{0}" is an invalid JSON file.'.format(SAVE_FILE)
print(str)
return str
async def save(self, save_to_file=True):
dump = {}
for key, value in self._client.ongoing_riddles.items():
dump_channel = dict(value)
dump_channel["message"] = dump_channel["message"].id
dump[key.id] = dump_channel
os.makedirs(os.path.dirname(SAVE_FILE), exist_ok=True)
with open(SAVE_FILE, "w") as file:
json.dump(dump, file, ensure_ascii=False)
print('Saved fouras riddles state in file "{0}"'.format(SAVE_FILE))
return dump
def new_riddle(self, channel, index):
current_riddle = dict(
index=index,
nbClues=-1,
riddle=self._client.riddles[index].strip(),
answer=self._client.answers[index],
)
self._client.ongoing_riddles[channel] = current_riddle
return self.format_message(current_riddle)
def finish_riddle(self, channel):
del self._client.ongoing_riddles[channel]
def clue_string(self, 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(self, 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(
self.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> Qui suis-je ?\n{2}".format(
current_riddle["index"] + 1, formatted_riddle, clue
)
else:
return "Énigme {0}:\n{1}\n> Qui suis-je ?".format(
current_riddle["index"] + 1, formatted_riddle
)
async def handle_message(self, message) -> bool:
if message.author == self._client.user:
return False
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(self._client.riddles):
if random.random() <= 0.03:
await message.channel.send("Non")
else:
await message.channel.send(self.new_riddle(message.channel, index))
else:
await message.channel.send(
INVALID_ID.format(len=len(self._client.riddles))
)
return True
if message_content == "fouras":
if random.random() <= 0.03:
await message.channel.send("Non")
elif len(self._client.riddles) > 0:
index = random.randint(0, len(self._client.riddles) - 1)
await message.channel.send(self.new_riddle(message.channel, index))
return True
if message_content.startswith("bug"):
author_user = await self._client.fetch_user(MAINTAINER_ID)
channel_name = await self.get_channel_name(message.channel)
messages_json = await self.load_history(message.channel)
await author_user.send(
BUG_REPORT.format(
user=message.author.mention,
user_id=message.author.id,
channel=channel_name,
channel_id=message.channel.id,
message=message_content,
history=messages_json,
state=self.save(False)
)
)
await message.channel.send(f'Rapport de bug envoyé à {author_user.mention}\nMerci de ton feedback !')
return True
broadcast_match = re.match(r"^broadcast\s+(\d+) (.*)", message.content)
if broadcast_match and message.author.id == MAINTAINER_ID:
index = int(broadcast_match.group(1))
broadcast_message = broadcast_match.group(2)
channel = await self._client.fetch_channel(index)
if channel:
await channel.send(broadcast_message)
else:
await message.channel.send(f'Invalid channel id : {index}')
return True
if message_content == "about fouras":
author_user = await self._client.fetch_user(MAINTAINER_ID)
await message.channel.send(
ABOUT.format(user=author_user.mention, url=API_URL)
)
return True
if message_content == "save fouras":
if(message.author.id == 151626081458192384):
json_str = "```json\n{0}```".format(json.dumps(self.save(), ensure_ascii=False, indent=2))
await message.author.send(json_str)
return True
if message_content == "load fouras":
if(message.author.id == 151626081458192384):
await self.load()
await message.author.send(
"Loaded {0} riddles".format(len(self._client.riddles))
)
return True
if message_content == "debug fouras":
if(message.author.id == 151626081458192384):
dump = {}
for key, value in self._client.ongoing_riddles.items():
dump_channel = dict(value)
dump_channel.pop("message", None)
dump_channel.pop("answer", None)
channel_name = await self.get_channel_name(key)
dump[channel_name] = dump_channel
await message.author.send(
"```json\n{0}```".format(json.dumps(dump, ensure_ascii=False, indent=4))
)
return True
# if current channel has ongoing riddle
if message.channel in self._client.ongoing_riddles:
current_riddle = self._client.ongoing_riddles[message.channel]
if "message" in current_riddle:
answer = current_riddle["answer"]
if unidecode(answer.lower()) in unidecode(message_content):
current_riddle["solver"] = message.author
await message.channel.send(
SUCCESS.format(user=message.author.mention, answer=answer)
)
await current_riddle["message"].edit(
content=self.format_message(current_riddle)
)
self.finish_riddle(message.channel)
return True
if (
message_content == "repete"
or message_content == "répète"
or message_content == "repeat"
):
current_riddle.pop("message")
await message.channel.send(self.format_message(current_riddle))
return True
# 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 == "help"
or message_content == "clue"
):
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=self.format_message(current_riddle)
)
if nbClues >= len(answer):
self.finish_riddle(message.channel)
return True
return False