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://git.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