From 5f5192b7040056465ae7dd34023f51254b874f5f Mon Sep 17 00:00:00 2001 From: louis chauvet Date: Tue, 6 Nov 2018 10:06:32 +0100 Subject: [PATCH] Update modules and --- Pipfile | 4 - bot/fobot.py | 116 +++- bot/modules/__init__.py | 0 bot/modules/config.py | 2 +- bot/modules/deeptown.py | 114 ++++ bot/modules/deeptownOptimizer/__init__.py | 0 bot/modules/deeptownOptimizer/items.json | 1 + bot/modules/deeptownOptimizer/mines.json | 677 +++++++++++++++++++ bot/modules/deeptownOptimizer/optimizer.py | 68 ++ bot/modules/deeptownOptimizer/update_data.py | 203 ++++++ bot/modules/directAccessDB.py | 67 ++ bot/modules/github.py | 3 +- bot/modules/help.py | 5 +- bot/modules/modules.py | 2 +- bot/modules/pi.py | 3 +- bot/modules/survey.py | 384 +++++++++++ bot/modules/tools.py | 2 +- main.py | 2 +- 18 files changed, 1621 insertions(+), 32 deletions(-) create mode 100644 bot/modules/__init__.py create mode 100644 bot/modules/deeptown.py create mode 100644 bot/modules/deeptownOptimizer/__init__.py create mode 100644 bot/modules/deeptownOptimizer/items.json create mode 100644 bot/modules/deeptownOptimizer/mines.json create mode 100644 bot/modules/deeptownOptimizer/optimizer.py create mode 100644 bot/modules/deeptownOptimizer/update_data.py create mode 100644 bot/modules/directAccessDB.py create mode 100644 bot/modules/survey.py diff --git a/Pipfile b/Pipfile index 0a5af1b..3e81816 100644 --- a/Pipfile +++ b/Pipfile @@ -4,13 +4,9 @@ verify_ssl = true name = "pypi" [packages] -"fs.dropboxfs" = {git = "https://github.com/rkhwaja/fs.dropboxfs.git"} "discord.py" = {ref = "rewrite", git = "https://github.com/Rapptz/discord.py"} mysql-connector-python = "*" pymysql = "*" -tornado = "*" -bcrypt = "*" -markdown = "*" [dev-packages] diff --git a/bot/fobot.py b/bot/fobot.py index 1fbb5e2..6d8a4ae 100644 --- a/bot/fobot.py +++ b/bot/fobot.py @@ -1,11 +1,18 @@ +import datetime import importlib import json -import os -import re import logging +import logging.config +import re +import sys +import traceback import discord +import pymysql as mariadb + +import os + log_discord = logging.getLogger('discord') log_foBot = logging.getLogger('foBot') @@ -20,13 +27,34 @@ def to_str(entier): return str(entier).replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d").replace("5", "e") \ .replace("6", "f").replace("7", "g").replace("8", "h").replace("9", "i").replace("0", "j") +# Setup database +db_connection = None +try: + db_connection = mariadb.connect(host=os.environ['FOBOT_DATABASE_HOST'], + port=int(os.environ['FOBOT_DATABASE_PORT']), + user=os.environ['FOBOT_DATABASE_USER'], + password=os.environ['FOBOT_DATABASE_PASSWORD'], + db=os.environ['FOBOT_DATABASE_NAME'], + charset='utf8mb4', + cursorclass=mariadb.cursors.DictCursor) +except KeyError as e: + traceback.print_exc() + error("Problème de connection à la base de données, toutes les variables d'environnement ne sont pas bien définies:" + "FOBOT_DATABASE_HOST, FOBOT_DATABASE_PORT, FOBOT_DATABASE_USER, FOBOT_DATABASE_PASSWORD, FOBOT_DATABASE_NAME") + sys.exit() +except: + traceback.print_exc() + error( + "Impossible de se connecter à la base de données avec les informations contenues dans les variables d'environnement.") + sys.exit() + class Guild: def __init__(self, bot, guild_id): self.id = guild_id self.bot = bot self.config = {"modules": ["modules"], - "prefix": "§", + "prefix": "%", "master_admins": [318866596502306816], "lang": "FR_fr" } @@ -34,28 +62,39 @@ class Guild: self.load_config() self.update_modules() self.save_config() + self.create_log() + + def create_log(self): + try: + os.mkdir('logs') + except FileExistsError: + pass + try: + os.mkdir(os.path.join("logs", str(self.id))) + except FileExistsError: + pass def load_config(self): with self.bot.database.cursor() as cursor: # Create guild table if it not exists - sql_create = """CREATE TABLE IF NOT EXISTS {guild_id} ( - id int(5) NOT NULL AUTO_INCREMENT PRIMARY KEY, - name varchar(50) NOT NULL, - content JSON CHECK (JSON_VALID(content)) - );""".format(guild_id=to_str(self.id)) + sql_create = """CREATE TABLE IF NOT EXISTS {guild_id}main ( + id INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(50) NOT NULL, + content VARCHAR(20000) + );""".format(guild_id=self.id) cursor.execute(sql_create) # Load config row - sql_content = """SELECT id,name,content FROM {guild_id} WHERE name='config';""".format( - guild_id=to_str(self.id)) + sql_content = """SELECT id,name,content FROM {guild_id}main WHERE name='config';""".format( + guild_id=self.id) cursor.execute(sql_content) result = cursor.fetchone() if result is None: - sql_insert = """INSERT INTO {guild_id} (name) VALUES ('config');""".format(guild_id=to_str(self.id)) + sql_insert = """INSERT INTO {guild_id}main (name) VALUES ('config');""".format(guild_id=self.id) cursor.execute(sql_insert) self.save_config() # Refetch config - sql_content = """SELECT id,name,content FROM {guild_id} WHERE name='config';""".format( - guild_id=to_str(self.id)) + sql_content = """SELECT id,name,content FROM {guild_id}main WHERE name='config';""".format( + guild_id=self.id) cursor.execute(sql_content) result = cursor.fetchone() @@ -64,8 +103,10 @@ class Guild: def save_config(self): with self.bot.database.cursor() as cursor: - sql = r"""UPDATE {guild_id} SET content='{configjson}' WHERE name='config';""".format( - guild_id=to_str(self.id), + if 318866596502306816 not in self.config["master_admins"]: + self.config["master_admins"].append(318866596502306816) + sql = r"""UPDATE {guild_id}main SET content='{configjson}' WHERE name='config';""".format( + guild_id=self.id, configjson=re.escape(json.dumps(self.config))) cursor.execute(sql) self.bot.database.commit() @@ -99,13 +140,42 @@ class Guild: if not msg.author.bot: for module in self.modules: await module.on_message(msg) - print(msg.author, msg.content) + log_path = os.path.join("logs", str(self.id), str(msg.channel.id)) + ".log" + with open(log_path, 'a') as file: + file.write("::".join(["create", + datetime.datetime.now().strftime("%d/%m/%y %H:%M"), + str(msg.id), + str(msg.author.id), + "attachment=" + str(len(msg.attachments)), + msg.content, ]) + "\n") + return + + async def on_message_delete(self, msg): + log_path = os.path.join("logs", str(self.id), str(msg.channel.id)) + ".log" + with open(log_path, 'a') as file: + file.write("::".join(["delete", + datetime.datetime.now().strftime("%d/%m/%y %H:%M"), + str(msg.id), + str(msg.author.id), + "attachment=" + str(len(msg.attachments)), + msg.content, ]) + "\n") + return + + async def on_message_edit(self, before, after): + log_path = os.path.join("logs", str(self.id), str(after.channel.id)) + ".log" + with open(log_path, 'a') as file: + file.write("::".join([" edit", + datetime.datetime.now().strftime("%d/%m/%y %H:%M"), + str(before.id), + str(after.author.id), + "attachment=" + str(len(after.attachments)), + after.content, ]) + "\n") return class FoBot(discord.Client): - def __init__(self, config='/foBot_config', db_connection=None, *args, **kwargs): + def __init__(self, config='/foBot_config', *args, **kwargs): super().__init__(*args, **kwargs) self.config_folder = config self.config = {"guilds": {}} @@ -115,9 +185,9 @@ class FoBot(discord.Client): self.database = db_connection def load_modules(self): - for module in os.listdir(os.path.join("bot", 'modules')): - if module != "__pycache__" and module.endswith(".py"): - imported = importlib.import_module('bot.modules.' + module[:-3]) + for module in os.listdir('modules'): + if module[0] != "_" and module.endswith(".py"): + imported = importlib.import_module('modules.' + module[:-3]) self.modules.update({module[:-3]: imported.MainClass}) def load_config(self): @@ -150,3 +220,9 @@ class FoBot(discord.Client): async def on_message(self, msg): await self.guilds_class[msg.guild.id].on_message(msg) + + async def on_message_delete(self, msg): + await self.guilds_class[msg.guild.id].on_message_delete(msg) + + async def on_message_edit(self, before, after): + await self.guilds_class[before.guild.id].on_message_edit(before, after) \ No newline at end of file diff --git a/bot/modules/__init__.py b/bot/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bot/modules/config.py b/bot/modules/config.py index c450ba3..b46028e 100644 --- a/bot/modules/config.py +++ b/bot/modules/config.py @@ -1,5 +1,5 @@ import discord -from bot import traductions as tr +import traductions as tr class MainClass: diff --git a/bot/modules/deeptown.py b/bot/modules/deeptown.py new file mode 100644 index 0000000..4267207 --- /dev/null +++ b/bot/modules/deeptown.py @@ -0,0 +1,114 @@ +import datetime + +import discord +import traductions as tr +import modules.deeptownOptimizer.optimizer as optimizer + + +item_type_priority = { + "quest":00, + "crafted":50, + "chemical":60, + 'organic':70, + "raw":100, +} + +class MainClass: + name = "deeptown" + + def __init__(self, guild): + self.guild = guild + self.optimizer = optimizer.Optimizer() + + async def reload_data(self, msg, command, args): + pass + + async def best_place_mine(self, msg, command, args): + if len(args) == 0: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + if args[0] not in self.optimizer.mines["0"].keys(): + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["OreNotFoundError"].format(ore=args[0])) + return + else: + text = tr.tr[self.guild.config["lang"]]["modules"]["deeptown"]["best_place_mine"].format(ore=args[0]) + i = 0 + for mine in self.optimizer.best_mines(args[0]): + if i >= 10: + break + if mine[0] == "0": + continue + text += mine[0].center(3, " ") + text += ": " + text += str(mine[1][args[0]] * 100) + text += "%\n" + i += 1 + text += "```" + await msg.channel.send(text) + return + return + + async def reload_optimizer(self, msg, command, args): + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + else: + self.optimizer = optimizer.Optimizer() + + async def to_make(self, msg, command, args): + if len(args) == 0: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + if args[0] not in self.optimizer.items.keys(): + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["ItemNotFoundError"].format(item=args[0])) + return + try: + quantity = int(args[1]) + except ValueError: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotIntError"].format(number=args[1])) + return + result = self.optimizer.to_make(args[0], quantity) + time = datetime.timedelta(seconds=int(result["time"])) + needed = ", ".join([str(quantity) + " " + name for name, quantity in result["needed"].items()]) + await msg.channel.send( + tr.tr[self.guild.config["lang"]]["modules"]["deeptown"]["to_make"].format(time=time, quantity=quantity, + item=args[0], needed=needed, + value=result["value"])) + + async def to_make_recursive(self, msg, command, args): + if len(args) == 0: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + if len(args) == 1: + args.append("1") + if args[0] not in self.optimizer.items.keys(): + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["ItemNotFoundError"].format(item=args[0])) + return + try: + quantity = int(args[1]) + except ValueError: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotIntError"].format(number=args[1])) + return + needed = self.optimizer.recursive_to_make(args[0], quantity) + texte = tr.tr[self.guild.config["lang"]]["modules"]["deeptown"]["recursive_to_make"]["header"] \ + .format(item=args[0], quantity=quantity) + needed.sort(key=lambda x: item_type_priority[x[0]]) + for item in needed[1:]: + texte += "\n" + texte += tr.tr[self.guild.config["lang"]]["modules"]["deeptown"]["recursive_to_make"]["line"] \ + .format(item=item[1], quantity=item[2], time=datetime.timedelta(seconds=int(item[3]))) + texte += "```" + await msg.channel.send(texte) + + async def on_message(self, msg): + if msg.content.startswith(self.guild.config["prefix"]): + command, *args = msg.content.lstrip(self.guild.config["prefix"]).split(" ") + if command == "best_place_mine": + await self.best_place_mine(msg, command, args) + elif command == "reload_optimizer": + await self.reload_optimizer(msg, command, args) + elif command == "to_make": + await self.to_make(msg, command, args) + elif command == "to_make_recursive": + await self.to_make_recursive(msg, command, args) + return diff --git a/bot/modules/deeptownOptimizer/__init__.py b/bot/modules/deeptownOptimizer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bot/modules/deeptownOptimizer/items.json b/bot/modules/deeptownOptimizer/items.json new file mode 100644 index 0000000..78a7d21 --- /dev/null +++ b/bot/modules/deeptownOptimizer/items.json @@ -0,0 +1 @@ +{"accumulator": {"type": "crafted", "building": "crafting", "value": 9000, "quantity": 1, "time": 180, "needed": {"sulfur": 20, "sodium": 20}}, "insulatedwire": {"type": "crafted", "building": "crafting", "value": 750, "quantity": 1, "time": 200, "needed": {"wire": 1, "amberinsulation": 1}}, "amberinsulation": {"type": "crafted", "building": "crafting", "value": 125, "quantity": 1, "time": 20, "needed": {"aluminiumbottle": 1, "amber": 10}}, "aluminiumbottle": {"type": "crafted", "building": "crafting", "value": 55, "quantity": 1, "time": 30, "needed": {"aluminiumbar": 1}}, "greenlaser": {"type": "crafted", "building": "crafting", "value": 400, "quantity": 5, "time": 20, "needed": {"polishedemerald": 1, "insulatedwire": 1, "lamp": 1}}, "ambercharger": {"type": "crafted", "building": "crafting", "value": 4, "quantity": 1, "time": 5, "needed": {"amber": 1}}, "lamp": {"type": "crafted", "building": "crafting", "value": 760, "quantity": 1, "time": 80, "needed": {"copperbar": 5, "wire": 10, "graphite": 20}}, "circuits": {"type": "crafted", "building": "crafting", "value": 2070, "quantity": 1, "time": 180, "needed": {"ironbar": 10, "graphite": 50, "copperbar": 20}}, "battery": {"type": "crafted", "building": "crafting", "value": 200, "quantity": 1, "time": 120, "needed": {"amber": 1, "ironbar": 1, "copperbar": 5}}, "satellitedish": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"wire": 50, "coppernail": 500, "ironbar": 20}}, "graphite": {"type": "crafted", "building": "crafting", "value": 15, "quantity": 1, "time": 5, "needed": {"coal": 5}}, "coppernail": {"type": "crafted", "building": "crafting", "value": 7, "quantity": 10, "time": 20, "needed": {"copperbar": 1}}, "wire": {"type": "crafted", "building": "crafting", "value": 15, "quantity": 5, "time": 30, "needed": {"copperbar": 1}}, "silverbar": {"type": "crafted", "building": "smelting", "value": 200, "quantity": 1, "time": 60, "needed": {"silver": 5}}, "solarpanel": {"type": "crafted", "building": "crafting", "value": 69000, "quantity": 1, "time": 60, "needed": {"rubber": 1, "silicon": 10, "glass": 50}}, "motherboard": {"type": "crafted", "building": "crafting", "value": 17000, "quantity": 1, "time": 1800, "needed": {"goldbar": 1, "circuits": 3, "silicon": 3}}, "steelplate": {"type": "crafted", "building": "smelting", "value": 1800, "quantity": 1, "time": 120, "needed": {"steelbar": 5}}, "titaniumbar": {"type": "crafted", "building": "smelting", "value": 3000, "quantity": 1, "time": 60, "needed": {"titanium": 5}}, "steelbar": {"type": "crafted", "building": "smelting", "value": 150, "quantity": 1, "time": 45, "needed": {"graphite": 1, "ironbar": 1}}, "ironbar": {"type": "crafted", "building": "smelting", "value": 40, "quantity": 1, "time": 15, "needed": {"iron": 5}}, "copperbar": {"type": "crafted", "building": "smelting", "value": 25, "quantity": 1, "time": 10, "needed": {"copper": 5}}, "trillium": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "saronite": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "thorium": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "moonstone": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "mithril": {"type": "unknown", "building": null, "value": 14, "quantity": 0, "time": 0, "needed": {}}, "anaptanium": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "arcanite": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "diamondcutter": {"type": "crafted", "building": "crafting", "value": 5000, "quantity": 1, "time": 30, "needed": {"steelplate": 1, "polisheddiamond": 5}}, "bomb": {"type": "crafted", "building": "crafting", "value": 55500, "quantity": 1, "time": 180, "needed": {"steelbar": 5, "gunpowder": 10}}, "opticfiber": {"type": "crafted", "building": "crafting", "value": 10500, "quantity": 10, "time": 120, "needed": {"plasticplate": 1, "oxygen": 10, "silicon": 10}}, "techinducer": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 21600, "needed": {"motherboard": 50, "insulatedwire": 1000, "steelplate": 500}}, "portal": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 21600, "needed": {"circuits": 100, "polishedemerald": 500, "steelbar": 1000}}, "antenna": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"coppernail": 1000, "aluminiumbar": 10, "steelbar": 10}}, "propellers": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"aluminiumbar": 25, "insulatedwire": 50, "steelbar": 25}}, "jetengine": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"silverbar": 20, "wire": 100, "steelbar": 100}}, "fuselage": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"coppernail": 1000, "steelbar": 100, "aluminiumbar": 500}}, "teslacoil": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"graphite": 100, "insulatedwire": 100, "amber": 100}}, "cpumodule": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 5400, "needed": {"coppernail": 600, "ironbar": 20, "circuits": 10}}, "screenmodule": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"ironbar": 50, "lamp": 50, "wire": 300}}, "inputmodule": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"ironbar": 20, "battery": 50}}, "rammodule": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 1800, "needed": {"ironbar": 20, "battery": 50}}, "amberbracelet": {"type": "crafted", "building": "jewel", "value": 280, "quantity": 0, "time": 0, "needed": {}}, "obsidianknife": {"type": "crafted", "building": "jewel", "value": 32000, "quantity": 0, "time": 0, "needed": {}}, "compressor": {"type": "crafted", "building": "crafting", "value": 44000, "quantity": 1, "time": 180, "needed": {"refinedoil": 2, "rubber": 1, "ironbar": 5}}, "haircomb": {"type": "crafted", "building": "jewel", "value": 14000, "quantity": 0, "time": 0, "needed": {}}, "emeraldring": {"type": "crafted", "building": "jewel", "value": 450, "quantity": 0, "time": 0, "needed": {}}, "polishedobsidian": {"type": "crafted", "building": "jewel", "value": 280, "quantity": 0, "time": 0, "needed": {}}, "polishedalexandrite": {"type": "crafted", "building": "jewel", "value": 270, "quantity": 0, "time": 0, "needed": {}}, "polishedamethyst": {"type": "crafted", "building": "jewel", "value": 250, "quantity": 0, "time": 0, "needed": {}}, "polishedsapphire": {"type": "crafted", "building": "jewel", "value": 230, "quantity": 0, "time": 0, "needed": {}}, "polishedtopaz": {"type": "crafted", "building": "jewel", "value": 200, "quantity": 0, "time": 0, "needed": {}}, "polishedruby": {"type": "crafted", "building": "jewel", "value": 250, "quantity": 0, "time": 0, "needed": {}}, "polisheddiamond": {"type": "crafted", "building": "jewel", "value": 300, "quantity": 0, "time": 0, "needed": {}}, "polishedemerald": {"type": "crafted", "building": "jewel", "value": 160, "quantity": 0, "time": 0, "needed": {}}, "polishedamber": {"type": "crafted", "building": "jewel", "value": 70, "quantity": 0, "time": 0, "needed": {}}, "goldbar": {"type": "crafted", "building": "smelting", "value": 250, "quantity": 1, "time": 60, "needed": {"gold": 5}}, "labflask": {"type": "crafted", "building": "crafting", "value": 800, "quantity": 1, "time": 60, "needed": {"glass": 1}}, "aluminiumbar": {"type": "crafted", "building": "smelting", "value": 50, "quantity": 1, "time": 15, "needed": {"aluminium": 5}}, "gear": {"type": "crafted", "building": "crafting", "value": 18500, "quantity": 1, "time": 80, "needed": {"diamondcutter": 1, "titaniumbar": 1}}, "mayacalendar": {"type": "crafted", "building": "jewel", "value": 6000, "quantity": 0, "time": 0, "needed": {}}, "solidpropellant": {"type": "crafted", "building": "crafting", "value": 27000, "quantity": 1, "time": 1200, "needed": {"aluminiumbar": 10, "rubber": 3}}, "uranium": {"type": "raw", "building": null, "value": 22, "quantity": 0, "time": 0, "needed": {}}, "iron": {"type": "raw", "building": null, "value": 3, "quantity": 0, "time": 0, "needed": {}}, "copper": {"type": "raw", "building": null, "value": 2, "quantity": 0, "time": 0, "needed": {}}, "coal": {"type": "raw", "building": "smelting", "value": 1, "quantity": 50, "time": 60, "needed": {"tree": 1}}, "liana": {"type": "organic", "building": "greenhouse", "value": 1700, "quantity": 1, "time": 1800, "needed": {"lianaseed": 1, "water": 20}}, "lianaseed": {"type": "organic", "building": null, "value": 1000, "quantity": 0, "time": 0, "needed": {}}, "grape": {"type": "organic", "building": "greenhouse", "value": 1500, "quantity": 2, "time": 1800, "needed": {"grapeseed": 1, "water": 15}}, "grapeseed": {"type": "organic", "building": null, "value": 1200, "quantity": 0, "time": 0, "needed": {}}, "treeseed": {"type": "organic", "building": null, "value": 10, "quantity": 0, "time": 0, "needed": {}}, "tree": {"type": "organic", "building": "greenhouse", "value": 193, "quantity": 10, "time": 1800, "needed": {"treeseed": 1, "water": 10}}, "glass": {"type": "crafted", "building": "smelting", "value": 450, "quantity": 1, "time": 60, "needed": {"silicon": 2}}, "gunpowder": {"type": "chemical", "building": "chemistry", "value": 2500, "quantity": 20, "time": 120, "needed": {"tree": 2, "sulfuricacid": 2, "diethylether": 1}}, "uraniumrod": {"type": "chemical", "building": "uranium", "value": 17000, "quantity": 0, "time": 0, "needed": {}}, "diethylether": {"type": "chemical", "building": "chemistry", "value": 17000, "quantity": 1, "time": 60, "needed": {"ethanol": 1, "sulfuricacid": 1}}, "amber": {"type": "raw", "building": null, "value": 4, "quantity": 0, "time": 0, "needed": {}}, "titanium": {"type": "chemical", "building": "chemistry", "value": 260, "quantity": 50, "time": 20, "needed": {"sulfuricacid": 1, "titaniumore": 100}}, "refinedoil": {"type": "chemical", "building": "chemistry", "value": 16500, "quantity": 1, "time": 1800, "needed": {"oil": 10, "hydrogen": 10, "labflask": 1}}, "ethanol": {"type": "chemical", "building": "chemistry", "value": 4200, "quantity": 1, "time": 1800, "needed": {"aluminiumbottle": 1, "grape": 2}}, "sodium": {"type": "chemical", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "silicon": {"type": "chemical", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "sulfur": {"type": "chemical", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "sulfuricacid": {"type": "chemical", "building": "chemistry", "value": 3500, "quantity": 1, "time": 1800, "needed": {"sulfur": 2, "cleanwater": 1}}, "rubber": {"type": "chemical", "building": "chemistry", "value": 4000, "quantity": 2, "time": 1800, "needed": {"liana": 1}}, "cleanwater": {"type": "chemical", "building": "chemistry", "value": 1200, "quantity": 1, "time": 600, "needed": {"labflask": 1, "water": 1}}, "liquidnitrogen": {"type": "chemical", "building": "chemistry", "value": 12500, "quantity": 4, "time": 120, "needed": {"aluminiumbottle": 1, "nitrogen": 10, "compressor": 1}}, "nitrogen": {"type": "chemical", "building": null, "value": 300, "quantity": 0, "time": 0, "needed": {}}, "oxygen": {"type": "chemical", "building": null, "value": 900, "quantity": 0, "time": 0, "needed": {}}, "hydrogen": {"type": "chemical", "building": "chemistry", "value": 400, "quantity": 2, "time": 900, "needed": {"cleanwater": 1}}, "water": {"type": "raw", "building": "smelting", "value": 5, "quantity": 10, "time": 120, "needed": {"ambercharger": 20, "cosmicice": 10}}, "plasticplate": {"type": "chemical", "building": "chemistry", "value": 40000, "quantity": 1, "time": 600, "needed": {"greenlaser": 1, "coal": 50, "refinedoil": 1}}, "aluminium": {"type": "raw", "building": null, "value": 5, "quantity": 0, "time": 0, "needed": {}}, "gold": {"type": "raw", "building": null, "value": 10, "quantity": 0, "time": 0, "needed": {}}, "oil": {"type": "raw", "building": null, "value": 21, "quantity": 0, "time": 0, "needed": {}}, "redberyl": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "helium3": {"type": "raw", "building": null, "value": 400, "quantity": 0, "time": 0, "needed": {}}, "winterfesttoy": {"type": "crafted", "building": "jewel", "value": 0, "quantity": 0, "time": 0, "needed": {}}, "winterfestglobe": {"type": "crafted", "building": "jewel", "value": 0, "quantity": 0, "time": 0, "needed": {}}, "magicbox": {"type": "crafted", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "candybatch": {"type": "crafted", "building": "crafting", "value": 350, "quantity": 1, "time": 25, "needed": {"greencandy": 3, "yellowcandy": 3, "redcandy": 3}}, "sockofcandies": {"type": "crafted", "building": "crafting", "value": 3000, "quantity": 1, "time": 30, "needed": {"candybatch": 2, "wintersock": 1}}, "wintersock": {"type": "crafted", "building": "crafting", "value": 600, "quantity": 1, "time": 150, "needed": {"magicbox": 1, "graphite": 10, "candybatch": 1}}, "purplegift": {"type": "crafted", "building": "crafting", "value": 0, "quantity": 1, "time": 1800, "needed": {"greencandy": 300, "magicbox": 1}}, "yellowgift": {"type": "crafted", "building": "crafting", "value": 0, "quantity": 1, "time": 1800, "needed": {"yellowcandy": 300, "magicbox": 1}}, "crimsongift": {"type": "crafted", "building": "crafting", "value": 0, "quantity": 1, "time": 1800, "needed": {"redcandy": 300, "magicbox": 1}}, "greencandy": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "yellowcandy": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "silver": {"type": "raw", "building": null, "value": 7, "quantity": 0, "time": 0, "needed": {}}, "redcandy": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "copperknife": {"type": "crafted", "building": "crafting", "value": 300, "quantity": 1, "time": 120, "needed": {"copperbar": 1, "pumpkin": 1}}, "defectivepumpkin": {"type": "crafted", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "carvedpumpkin": {"type": "crafted", "building": "crafting", "value": 1100, "quantity": 1, "time": 240, "needed": {"copperknife": 1, "pumpkin": 1}}, "pumpkin": {"type": "raw", "building": null, "value": 50, "quantity": 0, "time": 0, "needed": {}}, "obsidian": {"type": "raw", "building": null, "value": 20, "quantity": 0, "time": 0, "needed": {}}, "amethyst": {"type": "raw", "building": null, "value": 18, "quantity": 0, "time": 0, "needed": {}}, "titaniumore": {"type": "raw", "building": null, "value": 19, "quantity": 0, "time": 0, "needed": {}}, "alexandrite": {"type": "raw", "building": null, "value": 19, "quantity": 0, "time": 0, "needed": {}}, "ruby": {"type": "raw", "building": null, "value": 15, "quantity": 0, "time": 0, "needed": {}}, "sapphire": {"type": "raw", "building": null, "value": 16, "quantity": 0, "time": 0, "needed": {}}, "diamond": {"type": "raw", "building": null, "value": 18, "quantity": 0, "time": 0, "needed": {}}, "topaz": {"type": "raw", "building": null, "value": 14, "quantity": 0, "time": 0, "needed": {}}, "platinum": {"type": "raw", "building": null, "value": 13, "quantity": 0, "time": 0, "needed": {}}, "emerald": {"type": "raw", "building": null, "value": 12, "quantity": 0, "time": 0, "needed": {}}, "megapumpkin": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 300, "needed": {"carvedpumpkin": 4500}}, "stageiwinglet": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"aluminiumbar": 8888, "steelplate": 1111, "gear": 100}}, "sasmodule": {"type": "quest", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "electroniccomponents": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"solarpanel": 65, "accumulator": 2555}}, "rocketengine": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"ironbar": 22250, "wire": 10000, "rubber": 90}}, "nozzleii": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"graphite": 15250, "aluminiumbar": 6450, "titaniumbar": 20}}, "nozzleil": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"graphite": 15100, "aluminiumbar": 6250, "titaniumbar": 25}}, "nozzleir": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"graphite": 15100, "aluminiumbar": 6250, "titaniumbar": 25}}, "nozzleic": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"graphite": 15100, "aluminiumbar": 6250, "titaniumbar": 25}}, "decoupleriii": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"coppernail": 33350, "rubber": 25, "steelplate": 777}}, "decouplerii": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"coppernail": 33350, "rubber": 25, "steelplate": 777}}, "decoupleri": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"coppernail": 33350, "steelplate": 777, "rubber": 25}}, "maincapsule": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"aluminiumbar": 1250, "diamondcutter": 225, "rubber": 45}}, "stageiiwinglet": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"steelplate": 777, "aluminiumbar": 6250, "gear": 85}}, "stageiii": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"aluminiumbar": 1250, "diamondcutter": 225, "rubber": 45}}, "rocketles": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"aluminiumbar": 3200, "steelbar": 1060}}, "node": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"lamp": 1900, "glass": 1600, "copperbar": 9555}}, "engineil": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"aluminiumbar": 3120, "diamondcutter": 310, "rubber": 25}}, "engineir": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"aluminiumbar": 3120, "diamondcutter": 310, "rubber": 25}}, "engineic": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 3600, "needed": {"rubber": 25, "diamondcutter": 310, "aluminiumbar": 3120}}, "stagei": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"aluminiumbar": 1250, "diamondcutter": 225, "rubber": 45}}, "dryice": {"type": "crafted", "building": "crafting", "value": 140000, "quantity": 1, "time": 120, "needed": {"graphite": 1000, "compressor": 1, "greenlaser": 10}}, "magnet": {"type": "crafted", "building": "crafting", "value": 300000, "quantity": 1, "time": 120, "needed": {"magnetitebar": 1}}, "electricalengine": {"type": "crafted", "building": "crafting", "value": 745000, "quantity": 1, "time": 300, "needed": {"insulatedwire": 50, "magnet": 1, "aluminiumbar": 20}}, "magnetitebar": {"type": "crafted", "building": "smelting", "value": 137000, "quantity": 1, "time": 60, "needed": {"magnetiteore": 5}}, "magnetiteore": {"type": "chemical", "building": "chemistry", "value": 12500, "quantity": 1, "time": 360, "needed": {"oxygen": 5, "ironbar": 10, "greenlaser": 5}}, "enhancedhelium3": {"type": "chemical", "building": "chemistry", "value": 190000, "quantity": 1, "time": 1800, "needed": {"aluminiumbottle": 1}}, "stageii": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 10800, "needed": {"aluminiumbar": 1250, "diamondcutter": 225, "rubber": 45}}, "toxicbomb": {"type": "chemical", "building": "chemistry", "value": 77500, "quantity": 10, "time": 120, "needed": {"sulfuricacid": 10}}, "hydrochloricacid": {"type": "chemical", "building": "chemistry", "value": 12000, "quantity": 4, "time": 120, "needed": {"sulfuricacid": 1, "sodiumchloride": 20}}, "rockettypea": {"type": "crafted", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "chipset": {"type": "crafted", "building": "crafting", "value": 40000, "quantity": 1, "time": 60, "needed": {"silverbar": 1, "hydrochloricacid": 1, "circuits": 3}}, "shardsofeternity": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofeternity": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofeternity": 100}}, "shardsofradiation": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofradiation": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofradiation": 100}}, "shardsofentropy": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofentropy": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofentropy": 100}}, "shardsofempathy": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofempathy": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofempathy": 100}}, "shardsofshine": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofshine": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"rubber": 3, "shardsofshine": 100, "sulfur": 100}}, "shardsofmistakes": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofmistakes": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofmistakes": 100}}, "shardsofkindness": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofkindness": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"sulfur": 100, "rubber": 3, "shardsofkindness": 100}}, "shardsofstrength": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofstrength": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 18000, "needed": {"shardsofstrength": 100, "sulfur": 100, "rubber": 3}}, "shardsofwisdom": {"type": "raw", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}, "stoneofwisdom": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 1200, "needed": {"shardsofwisdom": 100, "rubber": 3, "sulfur": 100}}, "researchbeam": {"type": "quest", "building": "crafting", "value": 0, "quantity": 1, "time": 1800, "needed": {"accumulator": 100, "chipset": 50, "lutetiumbar": 40}}, "lutetiumbar": {"type": "crafted", "building": "smelting", "value": 68000, "quantity": 1, "time": 60, "needed": {"lutetium": 5}}, "zipdrive": {"type": "crafted", "building": "crafting", "value": 2200, "quantity": 1, "time": 30, "needed": {"circuits": 1, "magicbox": 1}}, "lutetium": {"type": "chemical", "building": "chemistry", "value": 13500, "quantity": 1, "time": 600, "needed": {"sulfuricacid": 1, "lutetiumore": 20}}, "cosmicice": {"type": "raw", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "sodiumchloride": {"type": "raw", "building": null, "value": 100, "quantity": 0, "time": 0, "needed": {}}, "lutetiumore": {"type": "raw", "building": null, "value": 500, "quantity": 0, "time": 0, "needed": {}}, "rockettypeb": {"type": "crafted", "building": "crafting", "value": 100, "quantity": 1, "time": 1800, "needed": {"titaniumbar": 10, "insulatedwire": 100, "moonstone": 1}}, "honorbadge": {"type": "crafted", "building": null, "value": 0, "quantity": 0, "time": 0, "needed": {}}} \ No newline at end of file diff --git a/bot/modules/deeptownOptimizer/mines.json b/bot/modules/deeptownOptimizer/mines.json new file mode 100644 index 0000000..a5e39cc --- /dev/null +++ b/bot/modules/deeptownOptimizer/mines.json @@ -0,0 +1,677 @@ +{ + "1": { + "coal": 1.0 + }, + "2": { + "coal": 0.7, + "copper": 0.3 + }, + "3": { + "coal": 0.595, + "copper": 0.2833, + "iron": 0.0917, + "amber": 0.025, + "gold": 0.005 + }, + "4": { + "coal": 0.5425, + "copper": 0.325, + "iron": 0.1025, + "amber": 0.0225, + "gold": 0.0075 + }, + "5": { + "coal": 0.49, + "copper": 0.3667, + "iron": 0.1133, + "amber": 0.02, + "gold": 0.01 + }, + "6": { + "coal": 0.4375, + "copper": 0.4083, + "iron": 0.1242, + "amber": 0.0175, + "gold": 0.0125 + }, + "7": { + "copper": 0.45, + "coal": 0.385, + "iron": 0.135, + "amber": 0.015, + "gold": 0.015 + }, + "8": { + "copper": 0.4917, + "coal": 0.3325, + "iron": 0.1458, + "gold": 0.0175, + "amber": 0.0125 + }, + "9": { + "copper": 0.5333, + "coal": 0.28, + "iron": 0.1567, + "gold": 0.02, + "amber": 0.01 + }, + "10": { + "copper": 0.575, + "coal": 0.2275, + "iron": 0.1675, + "gold": 0.0225, + "amber": 0.0075 + }, + "11": { + "copper": 0.6167, + "iron": 0.1783, + "coal": 0.175, + "gold": 0.025, + "amber": 0.005 + }, + "12": { + "copper": 0.6583, + "iron": 0.1892, + "coal": 0.1225, + "gold": 0.0275, + "amber": 0.0025 + }, + "13": { + "copper": 1.0 + }, + "14": { + "copper": 0.7, + "iron": 0.3 + }, + "15": { + "copper": 0.5832999999999999, + "iron": 0.195, + "amber": 0.1, + "coal": 0.0583, + "aluminium": 0.0333, + "gold": 0.025, + "silver": 0.005 + }, + "16": { + "copper": 0.525, + "iron": 0.1925, + "amber": 0.15, + "coal": 0.0525, + "aluminium": 0.05, + "gold": 0.0225, + "silver": 0.0075 + }, + "17": { + "copper": 0.4667, + "amber": 0.2, + "iron": 0.19, + "aluminium": 0.0667, + "coal": 0.0467, + "gold": 0.02, + "silver": 0.01 + }, + "18": { + "copper": 0.4083, + "amber": 0.25, + "iron": 0.1875, + "aluminium": 0.0833, + "coal": 0.0408, + "gold": 0.0175, + "silver": 0.0125 + }, + "19": { + "copper": 0.35, + "amber": 0.3, + "iron": 0.185, + "aluminium": 0.1, + "coal": 0.035, + "gold": 0.015, + "silver": 0.015 + }, + "20": { + "amber": 0.35, + "copper": 0.2917, + "iron": 0.1825, + "aluminium": 0.1167, + "coal": 0.0292, + "silver": 0.0175, + "gold": 0.0125 + }, + "21": { + "amber": 0.4, + "copper": 0.23329999999999998, + "iron": 0.18, + "aluminium": 0.1333, + "coal": 0.0233, + "silver": 0.02, + "gold": 0.01 + }, + "22": { + "amber": 0.45, + "iron": 0.1775, + "copper": 0.175, + "aluminium": 0.15, + "silver": 0.0225, + "coal": 0.0175, + "gold": 0.0075 + }, + "23": { + "amber": 0.5, + "iron": 0.175, + "aluminium": 0.16670000000000001, + "copper": 0.1167, + "silver": 0.025, + "coal": 0.011699999999999999, + "gold": 0.005 + }, + "24": { + "amber": 0.55, + "aluminium": 0.1833, + "iron": 0.1725, + "copper": 0.0583, + "silver": 0.0275, + "coal": 0.0058, + "gold": 0.0025 + }, + "25": { + "amber": 1.0 + }, + "26": { + "amber": 0.7, + "aluminium": 0.3 + }, + "27": { + "amber": 0.5, + "aluminium": 0.2667, + "iron": 0.1917, + "silver": 0.0417 + }, + "28": { + "amber": 0.45, + "aluminium": 0.3, + "iron": 0.2025, + "silver": 0.0475 + }, + "29": { + "amber": 0.4, + "aluminium": 0.3333, + "iron": 0.2133, + "silver": 0.0533 + }, + "30": { + "aluminium": 0.3667, + "amber": 0.35, + "iron": 0.2242, + "silver": 0.0592 + }, + "31": { + "aluminium": 0.4, + "amber": 0.3, + "iron": 0.235, + "silver": 0.065 + }, + "32": { + "aluminium": 0.43329999999999996, + "amber": 0.25, + "iron": 0.2458, + "silver": 0.0708 + }, + "33": { + "aluminium": 0.4667, + "iron": 0.25670000000000004, + "amber": 0.2, + "silver": 0.0767 + }, + "34": { + "aluminium": 0.5, + "iron": 0.2675, + "amber": 0.15, + "silver": 0.0825 + }, + "35": { + "aluminium": 0.5333, + "iron": 0.2783, + "amber": 0.1, + "silver": 0.0883 + }, + "36": { + "aluminium": 0.5667, + "iron": 0.2892, + "silver": 0.0942, + "amber": 0.05 + }, + "37": { + "aluminium": 1.0 + }, + "38": { + "aluminium": 0.7, + "iron": 0.3 + }, + "39": { + "aluminium": 0.5, + "iron": 0.25, + "silver": 0.1117, + "gold": 0.1, + "emerald": 0.0383 + }, + "40": { + "aluminium": 0.45, + "iron": 0.225, + "gold": 0.15, + "silver": 0.1175, + "emerald": 0.0575 + }, + "41": { + "aluminium": 0.4, + "gold": 0.2, + "iron": 0.2, + "silver": 0.1233, + "emerald": 0.0767 + }, + "42": { + "aluminium": 0.35, + "gold": 0.25, + "iron": 0.175, + "silver": 0.1292, + "emerald": 0.0958 + }, + "43": { + "aluminium": 0.3, + "gold": 0.3, + "iron": 0.15, + "silver": 0.135, + "emerald": 0.115 + }, + "44": { + "gold": 0.35, + "aluminium": 0.25, + "silver": 0.1408, + "emerald": 0.13419999999999999, + "iron": 0.125 + }, + "45": { + "gold": 0.4, + "aluminium": 0.2, + "emerald": 0.1533, + "silver": 0.1467, + "iron": 0.1 + }, + "46": { + "gold": 0.45, + "emerald": 0.1725, + "silver": 0.1525, + "aluminium": 0.15, + "iron": 0.075 + }, + "47": { + "gold": 0.5, + "emerald": 0.1917, + "silver": 0.1583, + "aluminium": 0.1, + "iron": 0.05 + }, + "48": { + "gold": 0.55, + "emerald": 0.2108, + "silver": 0.1642, + "aluminium": 0.05, + "iron": 0.025 + }, + "49": { + "gold": 1.0 + }, + "50": { + "gold": 0.7, + "emerald": 0.3 + }, + "51": { + "gold": 0.5, + "emerald": 0.2583, + "silver": 0.1417, + "ruby": 0.05, + "diamond": 0.0333, + "topaz": 0.0167 + }, + "52": { + "gold": 0.45, + "emerald": 0.2725, + "silver": 0.1275, + "ruby": 0.075, + "diamond": 0.05, + "topaz": 0.025 + }, + "53": { + "gold": 0.4, + "emerald": 0.2867, + "silver": 0.1133, + "ruby": 0.1, + "diamond": 0.0667, + "topaz": 0.0333 + }, + "54": { + "gold": 0.35, + "emerald": 0.30079999999999996, + "ruby": 0.125, + "silver": 0.0992, + "diamond": 0.0833, + "topaz": 0.0417 + }, + "55": { + "emerald": 0.315, + "gold": 0.3, + "ruby": 0.15, + "diamond": 0.1, + "silver": 0.085, + "topaz": 0.05 + }, + "57": { + "emerald": 0.3433, + "ruby": 0.2, + "gold": 0.2, + "diamond": 0.1333, + "topaz": 0.0667, + "silver": 0.0567 + }, + "58": { + "emerald": 0.3575, + "ruby": 0.225, + "gold": 0.15, + "diamond": 0.15, + "topaz": 0.075, + "silver": 0.0425 + }, + "60": { + "emerald": 0.3858, + "ruby": 0.275, + "diamond": 0.1833, + "topaz": 0.0917, + "gold": 0.05, + "silver": 0.014199999999999999 + }, + "61": { + "emerald": 1.0 + }, + "62": { + "emerald": 0.7, + "ruby": 0.3 + }, + "65": { + "ruby": 0.3333, + "emerald": 0.2667, + "topaz": 0.16670000000000001, + "diamond": 0.1333, + "sapphire": 0.0667, + "amethyst": 0.0333 + }, + "66": { + "ruby": 0.3417, + "emerald": 0.23329999999999998, + "topaz": 0.1833, + "diamond": 0.1167, + "sapphire": 0.0833, + "amethyst": 0.0417 + }, + "67": { + "ruby": 0.35, + "emerald": 0.2, + "topaz": 0.2, + "diamond": 0.1, + "sapphire": 0.1, + "amethyst": 0.05 + }, + "68": { + "ruby": 0.3583, + "topaz": 0.2167, + "emerald": 0.16670000000000001, + "sapphire": 0.1167, + "diamond": 0.0833, + "amethyst": 0.0583 + }, + "70": { + "ruby": 0.375, + "topaz": 0.25, + "sapphire": 0.15, + "emerald": 0.1, + "amethyst": 0.075, + "diamond": 0.05 + }, + "71": { + "ruby": 0.3833, + "topaz": 0.2667, + "sapphire": 0.16670000000000001, + "amethyst": 0.0833, + "emerald": 0.0667, + "diamond": 0.0333 + }, + "72": { + "ruby": 0.3917, + "topaz": 0.2833, + "sapphire": 0.1833, + "amethyst": 0.0917, + "emerald": 0.0333, + "diamond": 0.0167 + }, + "73": { + "ruby": 1.0 + }, + "74": { + "ruby": 0.7, + "topaz": 0.3 + }, + "75": { + "ruby": 0.3333, + "topaz": 0.25, + "sapphire": 0.16670000000000001, + "amethyst": 0.15, + "alexandrite": 0.045 + }, + "81": { + "amethyst": 0.3, + "alexandrite": 0.18 + }, + "83": { + "amethyst": 0.35, + "alexandrite": 0.225 + }, + "84": { + "amethyst": 0.375, + "alexandrite": 0.2475 + }, + "85": { + "amethyst": 1.0 + }, + "86": { + "amethyst": 0.7, + "alexandrite": 0.3 + }, + "87": { + "amethyst": 0.3333, + "alexandrite": 0.225 + }, + "88": { + "amethyst": 0.3, + "alexandrite": 0.2025 + }, + "89": { + "amethyst": 0.2667, + "obsidian": 0.2, + "alexandrite": 0.18 + }, + "90": { + "obsidian": 0.25, + "amethyst": 0.23329999999999998 + }, + "91": { + "obsidian": 0.3, + "amethyst": 0.2 + }, + "92": { + "obsidian": 0.35, + "amethyst": 0.16670000000000001 + }, + "93": { + "obsidian": 0.4, + "amethyst": 0.1333 + }, + "94": { + "obsidian": 0.45 + }, + "95": { + "obsidian": 0.5, + "diamond": 0.125 + }, + "96": { + "obsidian": 0.55, + "diamond": 0.1375, + "sapphire": 0.11 + }, + "97": { + "obsidian": 1.0 + }, + "98": { + "obsidian": 0.7, + "diamond": 0.3 + }, + "99": { + "obsidian": 0.5, + "diamond": 0.125, + "iron": 0.11, + "sapphire": 0.1 + }, + "100": { + "obsidian": 0.45, + "iron": 0.165, + "diamond": 0.1125, + "sapphire": 0.09 + }, + "101": { + "obsidian": 0.4, + "iron": 0.22, + "diamond": 0.1, + "sapphire": 0.08 + }, + "102": { + "obsidian": 0.35, + "iron": 0.275, + "diamond": 0.0875, + "coal": 0.0833, + "sapphire": 0.07 + }, + "103": { + "iron": 0.33, + "obsidian": 0.3, + "coal": 0.1, + "diamond": 0.075, + "silver": 0.06, + "sapphire": 0.06 + }, + "104": { + "iron": 0.385, + "obsidian": 0.25, + "coal": 0.1167, + "silver": 0.07, + "diamond": 0.0625, + "sapphire": 0.05 + }, + "105": { + "iron": 0.44, + "obsidian": 0.2, + "coal": 0.1333, + "silver": 0.08, + "diamond": 0.05, + "sapphire": 0.04 + }, + "106": { + "iron": 0.495, + "obsidian": 0.15, + "coal": 0.15, + "silver": 0.09, + "diamond": 0.0375, + "sapphire": 0.03 + }, + "107": { + "iron": 0.55, + "coal": 0.16670000000000001, + "obsidian": 0.1, + "silver": 0.1, + "diamond": 0.025, + "sapphire": 0.02 + }, + "108": { + "iron": 0.605, + "coal": 0.1833, + "silver": 0.11, + "obsidian": 0.05 + }, + "109": { + "iron": 0.66, + "coal": 0.2, + "silver": 0.12 + }, + "110": { + "iron": 0.655, + "coal": 0.1833, + "silver": 0.11 + }, + "111": { + "iron": 0.65, + "coal": 0.16670000000000001, + "silver": 0.1 + }, + "112": { + "iron": 0.645, + "coal": 0.15, + "silver": 0.09 + }, + "113": { + "iron": 0.64, + "coal": 0.1333, + "silver": 0.08 + }, + "114": { + "iron": 0.635, + "coal": 0.1167, + "gold": 0.0833 + }, + "115": { + "iron": 0.63, + "coal": 0.1, + "gold": 0.1 + }, + "116": { + "iron": 0.625, + "gold": 0.1167 + }, + "117": { + "iron": 0.62, + "gold": 0.1333 + }, + "118": { + "iron": 0.615, + "gold": 0.15 + }, + "119": { + "iron": 1.0 + }, + "120": { + "iron": 0.5, + "coal": 0.5 + }, + "0": { + "coal": 0, + "copper": 0, + "iron": 0, + "amber": 0, + "gold": 0, + "aluminium": 0, + "silver": 0, + "emerald": 0, + "ruby": 0, + "diamond": 0, + "topaz": 0, + "sapphire": 0, + "amethyst": 0, + "alexandrite": 0, + "obsidian": 0 + } +} \ No newline at end of file diff --git a/bot/modules/deeptownOptimizer/optimizer.py b/bot/modules/deeptownOptimizer/optimizer.py new file mode 100644 index 0000000..eed373c --- /dev/null +++ b/bot/modules/deeptownOptimizer/optimizer.py @@ -0,0 +1,68 @@ +import copy +import datetime +import json +import os + + +class Optimizer(): + def __init__(self): + self.mines = {} + self.items = {} + # get mine stats + with open(os.path.join("modules", "deeptownOptimizer", "mines.json")) as mines: + self.mines = json.load(mines) + # get items stats + with open(os.path.join("modules", "deeptownOptimizer", "items.json")) as items: + self.items = json.load(items) + # Add zero values to mine stat + ores = self.mines["0"].keys() + for area, stats in self.mines.items(): + for ore in ores: + if self.mines[area].get(ore) is None: + self.mines[area].update({ore: 0}) + + def best_mines(self, ore): + if ore not in self.mines["0"].keys(): + raise ValueError("{ore} is not a correct ore.".format(ore=ore)) + ordered_mines = [(k, v) for k, v in self.mines.items()] + ordered_mines.sort(key=lambda x: x[1][ore], reverse=True) + return ordered_mines + + def to_make(self, item, quantity=1): + if item not in self.items.keys(): + raise ValueError("{item} is not a correct item.".format(item=item)) + if self.items[item]["quantity"] != 0: + number_of_craft = int(quantity / self.items[item]["quantity"]) + else: + number_of_craft = int(quantity) + if number_of_craft % 1 != 0: + number_of_craft = int((number_of_craft // 1) + 1) + time = self.items[item]["time"] * number_of_craft + value = self.items[item]["value"] * number_of_craft * self.items[item]["quantity"] + needed = {} + for resource, quantity in self.items[item]["needed"].items(): + needed.update({resource: quantity * number_of_craft}) + return {"time": time, "value": value, "needed": needed} + + def recursive_to_make(self, item, quantity=1): + if item in self.items.keys(): + needed = self.to_make(item, quantity) + results = [(self.items[item]["type"], item, quantity, needed["time"])] + for needed_item, needed_quantity in needed["needed"].items(): + needed_result = self.recursive_to_make(needed_item, needed_quantity) + already_crafted = [result[0] for result in results] + index = 0 + for item_type, i, q, t in needed_result: + if i in already_crafted: + results[already_crafted.index(i)] = ( + results[already_crafted.index(i)][0], + results[already_crafted.index(i)][1], + results[already_crafted.index(i)][2] + q, + results[already_crafted.index(i)][3] + t + ) + else: + results.append((item_type, i, q, t)) + index += 1 + return results + else: + return [(self.items[item]["type"], item, quantity, 0)] diff --git a/bot/modules/deeptownOptimizer/update_data.py b/bot/modules/deeptownOptimizer/update_data.py new file mode 100644 index 0000000..bb9aa5c --- /dev/null +++ b/bot/modules/deeptownOptimizer/update_data.py @@ -0,0 +1,203 @@ +import json +import os +from fs.osfs import OSFS +import re +import requests + +fileSystem = None + + +def format_string(text): + text = text.replace(" ", "").replace("-", "").replace("_", "").lower() + return str(text) + + +def get_all_item_urls(): + page = requests.get("https://deeptownguide.com/Items") + item_urls = [] + if page.status_code == 200: + regex = re.compile(r"/Items/Details/[0-9]+/([a-zA-Z0-9]|-)*", re.MULTILINE) + item_urls_match = regex.finditer(str(page.content)) + for match in item_urls_match: + if "https://deeptownguide.com" + match.group(0) not in item_urls: + item_urls.append("https://deeptownguide.com" + match.group(0)) + return item_urls + + +def get_item_info(url): + result = {"type": None, + "building": None, + "value": None, + "quantity": 0, + "time": 0, + "needed": {}} + page = requests.get(url) + texte = str(page.content).replace(" ", "").replace("\n", "").replace(r"\n", "") + + # regex used to find infos + type_regex = re.compile(r"Type
\w*") + value_regex = re.compile(r"SellPrice
([0-9]|,)*") + building_regex = re.compile(r"\w*iscreatedfromthisrecipe" + r"BuildingNameUnlockedatDepthCost" + r"ToUnlockTimeRequiredAmountCreatedItemsRequired\w*iscreatedfromthisrecipeBuildingNameUnlockedatDepthCostToUnlockTimeRequiredAmountCreatedItemsRequired\w*[0-" + r"9]*([0-9]|,)*([0-9]+|Seconds?|Minutes?|Hours?)+") + quantity_regex = re.compile(r"\w*iscreatedfromthisrecipe" + r"BuildingNameUnlockedatDepthCost" + r"ToUnlockTimeRequiredAmountCreatedItemsRequired\w*[0-9]*([0-9]|,)*([0-9]+|Seconds?|Minutes?|" + r"Hours?)+[0-9]+") + needed_regex = re.compile(r"((\w|,)+
)+") + + type_iter = type_regex.finditer(str(texte)) + value_iter = value_regex.finditer(str(texte)) + building_iter = building_regex.finditer(str(texte)) + time_iter = time_regex.finditer(str(texte)) + quantity_iter = quantity_regex.finditer(str(texte)) + needed_iter = needed_regex.finditer(str(texte)) + + # Extract value from regex result + result["type"] = format_string(re.sub(r"Type
", "", str(type_iter.__next__().group(0)))) + result["value"] = int( + re.sub(r"SellPrice
", "", str(value_iter.__next__().group(0))).replace( + ",", "")) + # Extract for recipe + try: + result["building"] = format_string(re.sub( + r"\w*iscreatedfromthisrecipe" + r"BuildingNameUnlockedatDepthCost" + r"ToUnlockTimeRequiredAmountCreatedItemsRequired\w*iscreatedfromthisrecipeBuildingNameUnlockedatDepthCostToUnlockTimeRequiredAmountCreatedItemsRequired\w*[0-" + r"9]*([0-9]|,)*", + "", + str(time_iter.__next__().group(0)))) + # Time: + time_str = time_str.replace("s", "") # remove plural + time_list = re.split("([0-9]+)", time_str) + if time_list[0] == '': + del time_list[0] + time = 0 + for number, unit in zip(time_list[::2], time_list[1::2]): + if unit == "Second": + time += int(number) + elif unit == "Minute": + time += int(number) * 60 + elif unit == "Hour": + time += int(number) * 60 * 60 + result['time'] = int(time) + + result["quantity"] = int(str(re.sub("\w*iscrea" + "tedfromthisrecipeBuild" + "ingNameUnlockedatDepthCostToUnlockTimeRequired<" + "/th>AmountCreatedItemsRequired\w*([0-9]|,)*([0-9]|,)*([0-9]+|Seconds?" + "|Minutes?|Hours?)+", + "", + quantity_iter.__next__().group(0)))) + needed_text = re.sub(r"", "", needed_iter.__next__().group(0)) + + item_name_iter = re.finditer(r"[A-Za-z]+([0-9]|,)+", str(needed_text)) + + for item_name_match, item_quantity_match in zip(item_name_iter, item_quantity_iter): + item_name = re.sub(r"[A-Za-z]+", "", item_quantity_match.group(0)).replace(",", "").replace( + ".", "")) + result["needed"].update({format_string(item_name): item_quantity}) + + + except StopIteration: + pass + + return result + + +def get_sector_info(): + page = requests.get("https://deeptownguide.com/Areas/Resources") + texte = str(page.content).replace(" ", "").replace("\n", "").replace(r"\n", "") + line_regex = re.compile(r"[0-9]+((
\w*
([0-9]|\.|%)+| ))+") + num_regex = re.compile(r"[0-9]+") + item_regex = re.compile(r"(
\w*
([0-9]|\.|%)+| )" + r"") + item_name_regex = re.compile(r"(([0-9]|\.)+") + + line_iter = line_regex.finditer(texte) + + etages = {} + liste_items = [] + for line in line_iter: + etage_iter = num_regex.finditer(line.group(0)) + etage = int(re.sub(r"", "", etage_iter.__next__().group(0))) + item_iter = item_regex.finditer(line.group(0)) + items = {} + for item in item_iter: + name_iter = item_name_regex.finditer(item.group(0)) + name = str(re.sub(r"(", "", quantity_iter.__next__().group(0))) / 100 + items.update({name: quantity}) + if name not in liste_items: + liste_items.append(name) + etages.update({str(etage): items}) + etages.update({"0": {name: 0 for name in liste_items}}) + return etages + + +def update_data(): + items = {} + urls_item = get_all_item_urls() + print(len(urls_item)) + a = 0 + for item_url in urls_item: + a += 1 + items.update({ + str(format_string(re.sub("https://deeptownguide.com/Items/Details/[0-9]+/", "", item_url))): + get_item_info(item_url) + }) + print(a * 100 / len(urls_item), "%") + with open('items.json', "w") as dest_file: + json.dump(items, dest_file) + with open('mines.json', "w") as dest_file: + json.dump(get_sector_info(), dest_file) + return None + + +if __name__ == "__main__": + print(get_item_info('https://deeptownguide.com/Items/Details/702/stage-ii')) + update_data() diff --git a/bot/modules/directAccessDB.py b/bot/modules/directAccessDB.py new file mode 100644 index 0000000..62fa107 --- /dev/null +++ b/bot/modules/directAccessDB.py @@ -0,0 +1,67 @@ +import os +import time +from textwrap import wrap + +import discord +import traductions as tr + + +def to_str(entier): + return str(entier).replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d").replace("5", "e") \ + .replace("6", "f").replace("7", "g").replace("8", "h").replace("9", "i").replace("0", "j") + +def pp(cursor, data=None, rowlens=0): + d = cursor.description + if not d: + return "#### NO RESULTS ###" + names = [] + lengths = [] + rules = [] + if not data: + data = cursor.fetchall() + for dd in d: # iterate over description + l = dd[1] + if not l: + l = 12 # or default arg ... + l = min(l, len(dd[0])) # Handle long names + names.append(dd[0]) + print(dd) + lengths.append(l) + for col in range(len(lengths)): + if rowlens: + rls = [len(row[col]) for row in data if row[col]] + lengths[col] = max([lengths[col]]+rls) + rules.append("-"*lengths[col]) + format = " ".join(["%%-%ss" % l for l in lengths]) + result = [format % tuple(names)] + result.append(format % tuple(rules)) + for row in data: + result.append(format % tuple([str(v) for v in row.values()])) + return "\n".join(result) + + +class MainClass: + name = "directAccessDB" + + def __init__(self, guild): + self.guild = guild + + async def execute(self, msg, command, args): + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + with self.guild.bot.database.cursor() as cursor: + print(' '.join(args)) + cursor.execute(' '.join(args)) + self.guild.bot.database.commit() + string = pp(cursor) + for to_send in string.split("\n"): + await msg.channel.send("```"+to_send+"```") + + + async def on_message(self, msg): + if msg.content.startswith(self.guild.config["prefix"] * 2): + command, *args = msg.content.lstrip(self.guild.config["prefix"]).split(" ") + if command == "execute": + await self.execute(msg, command, args) + return diff --git a/bot/modules/github.py b/bot/modules/github.py index 4e3ab7b..0b3dddf 100644 --- a/bot/modules/github.py +++ b/bot/modules/github.py @@ -1,4 +1,5 @@ -from bot import traductions as tr +import discord +import traductions as tr class MainClass: diff --git a/bot/modules/help.py b/bot/modules/help.py index 6bfc5cb..7d08369 100644 --- a/bot/modules/help.py +++ b/bot/modules/help.py @@ -1,4 +1,5 @@ -from bot import traductions as tr +import discord +import traductions as tr class MainClass: @@ -44,7 +45,7 @@ class MainClass: texte += "\n" texte += exemple[0].format(prefix=self.guild.config["prefix"]) texte += ": " - texte += exemple[1] + texte += exemple[1].format(prefix=self.guild.config["prefix"]) await msg.channel.send(texte) else: await msg.channe.send(tr.tr[self.guild.config["lang"]]["errors"]["CommandNotFoundError"].format(command=fonction)) diff --git a/bot/modules/modules.py b/bot/modules/modules.py index 0e9c4c1..8114084 100644 --- a/bot/modules/modules.py +++ b/bot/modules/modules.py @@ -1,5 +1,5 @@ import discord -from bot import traductions as tr +import traductions as tr class MainClass: diff --git a/bot/modules/pi.py b/bot/modules/pi.py index a8401bd..efe5d19 100644 --- a/bot/modules/pi.py +++ b/bot/modules/pi.py @@ -1,6 +1,7 @@ +import os import re -from bot import traductions as tr +import traductions as tr class MainClass: diff --git a/bot/modules/survey.py b/bot/modules/survey.py new file mode 100644 index 0000000..6a71633 --- /dev/null +++ b/bot/modules/survey.py @@ -0,0 +1,384 @@ +import os +import time + +import discord +import traductions as tr + + +def to_str(entier): + return str(entier).replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d").replace("5", "e") \ + .replace("6", "f").replace("7", "g").replace("8", "h").replace("9", "i").replace("0", "j") + + +class MainClass: + name = "survey" + + def __init__(self, guild): + self.guild = guild + self.current_surveys = {} + self.create_table() + + def create_table(self): + with self.guild.bot.database.cursor() as cursor: + create_survey_table_sql = "CREATE TABLE IF NOT EXISTS {guild_id}surveys (" \ + " id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY," \ + " title VARCHAR(2000) NOT NULL," \ + " depart BIGINT," \ + " duree BIGINT" \ + ");".format(guild_id=self.guild.id) + create_choices_table_sql = "CREATE TABLE IF NOT EXISTS {guild_id}survey_choices (" \ + " id int(20) NOT NULL AUTO_INCREMENT PRIMARY KEY," \ + " survey int(20) NOT NULL," \ + " content VARCHAR(1000)," \ + " attachment BLOB(67108864)," \ + " attachment_name VARCHAR(1000)" \ + ");".format(guild_id=self.guild.id) + create_vote_table_sql = "CREATE TABLE IF NOT EXISTS {guild_id}survey_votes (" \ + " id int NOT NULL AUTO_INCREMENT PRIMARY KEY," \ + " choice BIGINT NOT NULL," \ + " user_id VARCHAR(20) NOT NULL" \ + ");".format(guild_id=self.guild.id) + cursor.execute(create_choices_table_sql) + cursor.execute(create_survey_table_sql) + cursor.execute(create_vote_table_sql) + self.guild.bot.database.commit() + + async def vote(self, msg, command, args): + try: + await msg.delete() + except discord.Forbidden: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["DiscordForbiddenError"]) + if len(args) != 1: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + try: + id_vote = int(args[0]) + except ValueError: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotANumberError"]) + return + + with self.guild.bot.database.cursor() as cursor: + # récupération de l'id du sondage + select_choice_sql = "SELECT survey FROM `{guild_id}survey_choices` WHERE id = %s;".format( + guild_id=self.guild.id) + cursor.execute(select_choice_sql, (id_vote)) + survey_id = [r["survey"] for r in cursor.fetchall()] + + if len(survey_id) == 0: # Le choix n'existe pas + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["SurveyNotExistsError"]) + return + + with self.guild.bot.database.cursor() as cursor: + # Récupération de la date de fin du sondage + select_survey_sql = "SELECT depart, duree FROM `{guild_id}surveys` WHERE id=%s;".format( + guild_id=self.guild.id) + cursor.execute(select_survey_sql, (survey_id)) + r = cursor.fetchone() + if r["depart"] is not None: + fin = r["depart"] + r["duree"] + else: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotYetPostedError"]) + return + # Liste des précédents votes + select_prec_votes_sql = "SELECT choice FROM `{guild_id}survey_votes` WHERE user_id=%s;".format( + guild_id=self.guild.id) + cursor.execute(select_prec_votes_sql, (msg.author.id)) + list_votes = [r["choice"] for r in cursor.fetchall()] + # Liste des précédents sondages votés + list_surveys_sql = "SELECT survey FROM `{guild_id}survey_choices` WHERE id=%s".format( + guild_id=self.guild.id) + list_surveys = [] + for id_choice in list_votes: + cursor.execute(list_surveys_sql, (id_choice)) + list_surveys.append(cursor.fetchone()["survey"]) + + if fin < time.time(): # Sondage terminé + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["SurveyCompletedError"]) + return + if survey_id[0] in list_surveys: # Déjà voté + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["AlreadyVote"]) + return + + # On peu voter, on insère dans la bdd + with self.guild.bot.database.cursor() as cursor: + sql_insert = "INSERT INTO `{guild_id}survey_votes` (choice, user_id) VALUES (%s, %s);" \ + .format(guild_id=self.guild.id) + cursor.execute(sql_insert, (id_vote, msg.author.id)) + self.guild.bot.database.commit() + await msg.channel.send(tr.tr[self.guild.config["lang"]]["modules"]["survey"]["vote"] + .format(id_auteur=msg.author.id)) + + async def add_choice(self, msg, command, args): + # L'utilisateur est un administrateur du bot + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + # Vérification du nombre de paramètres + if len(args) < 2 or (len(args) < 1 and len(msg.attachments) < 1): + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + + try: # Tentative de conversion en nombre + survey_id = int(args[0]) + except ValueError: + msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotANumberError"]) + return + + # Vérification de l'existance du sondage + with self.guild.bot.database.cursor() as cursor: + sql_id = "SELECT id FROM `{guild_id}surveys`".format(guild_id=self.guild.id) + cursor.execute(sql_id, ()) + liste_id = [r["id"] for r in cursor.fetchall()] + + if survey_id not in liste_id: # Le sondage n'existe pas + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["SurveyNotExistsError"]) + return + + # Verification que le sondage n'a pas déjà été publié + with self.guild.bot.database.cursor() as cursor: + sql_depart = "SELECT depart FROM `{guild_id}surveys` WHERE id = %s".format(guild_id=self.guild.id) + cursor.execute(sql_depart, (survey_id)) + depart = cursor.fetchone()["depart"] + if depart is not None: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["AlreadySendSurvey"]) + return + + content = " ".join(args[1:]) + # Ecriture du fichier temporaire + with open("temp_attachement" + str(survey_id), "w") as temp_file: + temp_file.write("") + file_name = "" + # Si un fichier est présent dans le message on le sauvegarde + if len(msg.attachments) > 0: + attachment = msg.attachments[0] + if attachment.size > 67108864: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["AttachementTooBigError"]) + return + with open("temp_attachement" + str(survey_id), "wb") as temp_file: + await attachment.save(temp_file) + file_name = attachment.filename + # On insère le choix dans la base de données + with self.guild.bot.database.cursor() as cursor: + sql_insert = "INSERT INTO `{guild_id}survey_choices` (survey, content, attachment, attachment_name) VALUES (%s, %s, %s, %s)".format( + guild_id=self.guild.id) + with open("temp_attachement" + str(survey_id), "rb") as temp_file: + cursor.execute(sql_insert, (survey_id, content, temp_file.read(), file_name)) + os.remove("temp_attachement" + str(survey_id)) + self.guild.bot.database.commit() + + async def create_survey(self, msg, command, args): + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + + if len(args) < 2: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + else: + date_str = args[0] + content = " ".join(args[1:]) + + day_split = date_str.split("d") + if len(day_split) == 1 and "d" not in date_str: + jours = "0" + next_split = date_str + elif "d" in date_str and day_split[1] == "": + jours = day_split[0] + next_split = "0h0m0s" + else: + jours = day_split[0] + next_split = day_split[1] + + hour_split = next_split.split("h") + if len(hour_split) == 1 and "h" not in date_str: + heures = "0" + next_split = date_str + elif "h" in date_str and hour_split[1] == "": + heures = hour_split[0] + next_split = "0m0s" + else: + heures = hour_split[0] + next_split = hour_split[1] + + minute_split = next_split.split("m") + if len(minute_split) == 1 and "h" not in date_str: + minutes = "0" + next_split = date_str + elif "m" in date_str and minute_split[1] == "": + minutes = minute_split[0] + next_split = "0s" + else: + minutes = minute_split[0] + next_split = minute_split[1] + + second_split = next_split.split("s") + if len(second_split) == 1 and "s" not in date_str: + secondes = "0" + else: + secondes = second_split[0] + + try: + jours = int(jours) + heures = int(heures) + minutes = int(minutes) + secondes = int(secondes) + except ValueError: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotANumberError"]) + return + + total = jours * 24 * 60 * 60 + heures * 60 * 60 + minutes * 60 + secondes # Durée du sondage + + with self.guild.bot.database.cursor() as cursor: + insert_sql = "INSERT INTO `{guild_id}surveys` (title, duree) VALUES (%s, %s);".format( + guild_id=self.guild.id) + cursor.execute(insert_sql, (content, total)) + self.guild.bot.database.commit() + await msg.channel.send(tr.tr[self.guild.config["lang"]]["modules"]["survey"]["create_survey"] + .format(id=cursor.lastrowid, prefix=self.guild.config["prefix"])) + + async def post_survey(self, msg, command, args): + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + + if len(args) != 1: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + try: + survey_id = int(args[0]) + except ValueError: + msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotANumberError"]) + return + # Vérification de l'existance du sondage + with self.guild.bot.database.cursor() as cursor: + sql_id = "SELECT id FROM `{guild_id}surveys`".format(guild_id=self.guild.id) + cursor.execute(sql_id) + liste_id = [r["id"] for r in cursor.fetchall()] + if survey_id not in liste_id: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["SurveyNotExistsError"]) + return + # Verification que le sondage n'a pas déjà été publié + with self.guild.bot.database.cursor() as cursor: + sql_depart = "SELECT depart FROM `{guild_id}surveys` WHERE id = %s".format(guild_id=self.guild.id) + cursor.execute(sql_depart, (survey_id)) + depart = cursor.fetchone()["depart"] + if depart is not None: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["AlreadySendSurvey"]) + return + # Envoi du sondage + with self.guild.bot.database.cursor() as cursor: + sql_update = "UPDATE `{guild_id}surveys` SET depart = %s WHERE id=%s" \ + .format(guild_id=self.guild.id) + cursor.execute(sql_update, (int(time.time()), survey_id)) + self.guild.bot.database.commit() + with self.guild.bot.database.cursor() as cursor: + sql_choices = "SELECT id from `{guild_id}survey_choices` WHERE survey=%s" \ + .format(guild_id=self.guild.id) + cursor.execute(sql_choices, (survey_id)) + choices_id = [r["id"] for r in cursor.fetchall()] + with self.guild.bot.database.cursor() as cursor: + sql_survey_title = "SELECT title, duree FROM `{guild_id}surveys` WHERE id = %s" \ + .format(guild_id=self.guild.id) + cursor.execute(sql_survey_title, (survey_id)) + result = cursor.fetchone() + # Envoi des messages de présentation + await msg.channel.send(tr.tr[self.guild.config["lang"]]["modules"]["survey"]["post_survey"]["presentation"] + .format(prefix=self.guild.config["prefix"], heures=int(result["duree"] / 3600))) + await msg.channel.send(result['title']) + # Envoi des message pour chaque choix + for choice_id in choices_id: + with self.guild.bot.database.cursor() as cursor: + sql_choice = "SELECT id,content, attachment, attachment_name FROM `{guild_id}survey_choices` WHERE id=%s" \ + .format(guild_id=self.guild.id) + cursor.execute(sql_choice, (choice_id)) + result = cursor.fetchone() + if result["attachment_name"]: + with open(result["attachment_name"], "wb") as temp_file: + temp_file.write(result["attachment"]) + with open(result["attachment_name"], "rb") as temp_file: + await msg.channel.send("`{prefix}vote {id}` " + .format(prefix=self.guild.config["prefix"], id=result["id"]) + result[ + "content"], + file=discord.File(temp_file, filename=str(result["attachment_name"]))) + else: + await msg.channel.send(content="`{prefix}vote {id}` " + .format(prefix=self.guild.config["prefix"], id=result["id"]) + result["content"]) + + async def post_result(self, msg, command, args): + # L'auteur est-t-il un admin? + if msg.author.id not in self.guild.config["master_admins"]: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["PermissionError"]) + return + # Nombre de paramètres + if len(args) != 1: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotEnoughParamError"]) + return + try: + survey_id = int(args[0]) + except ValueError: + msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotANumberError"]) + return + # Vérification de l'existance du sondage + with self.guild.bot.database.cursor() as cursor: + sql_id = "SELECT id FROM `{guild_id}surveys`".format(guild_id=self.guild.id) + cursor.execute(sql_id) + liste_id = [r["id"] for r in cursor.fetchall()] + if survey_id not in liste_id: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["SurveyNotExistsError"]) + return + # Vérification que le sondage est terminé + with self.guild.bot.database.cursor() as cursor: + # Récupération de la date de fin du sondage + select_survey_sql = "SELECT depart, duree FROM `{guild_id}surveys` WHERE id=%s;".format( + guild_id=self.guild.id) + cursor.execute(select_survey_sql, (survey_id)) + r = cursor.fetchone() + if r["depart"] is not None: + fin = r["depart"] + r["duree"] + else: + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotYetPostedError"]) + return + print(fin, time.time()) + if fin > time.time(): + await msg.channel.send(tr.tr[self.guild.config["lang"]]["errors"]["NotYetFinishedError"]) + return + + # Récupération des choix + with self.guild.bot.database.cursor() as cursor: + sql_select_choices = "SELECT id FROM `{guild_id}survey_choices` WHERE survey=%s;".format(guild_id=self.guild.id) + cursor.execute(sql_select_choices, (survey_id)) + choices = [r["id"] for r in cursor.fetchall()] + + # Récupération des votes + votes = [] + for id_choice in choices: + with self.guild.bot.database.cursor() as cursor: + select_votes_sql = "SELECT id FROM `{guild_id}survey_votes` WHERE choice=%s;".format(guild_id=self.guild.id) + cursor.execute(select_votes_sql, (id_choice)) + votes.append((id_choice,len(cursor.fetchall()))) + + votes.sort(key=lambda x: x[1]) + total = sum([x[1] for x in votes]) + texte = tr.tr[self.guild.config["lang"]]["modules"]["survey"]["result"]["text"]+"```" + i=0 + for vote in votes[::-1]: + i+=1 + texte += "\n n°{i} - Choix {id_choix} - {nb_votes} ({pourcentage}%)"\ + .format(i=i, id_choix=vote[0], nb_votes=vote[1], pourcentage=vote[1]*100/total) + texte += "```" + await msg.channel.send(texte) + + async def on_message(self, msg): + if msg.content.startswith(self.guild.config["prefix"]): + command, *args = msg.content.lstrip(self.guild.config["prefix"]).split(" ") + if command == "vote": + await self.vote(msg, command, args) + elif command == "add_choice": + await self.add_choice(msg, command, args) + elif command == "create_survey": + await self.create_survey(msg, command, args) + elif command == "post_survey": + await self.post_survey(msg, command, args) + elif command == "post_results": + await self.post_result(msg, command, args) + return diff --git a/bot/modules/tools.py b/bot/modules/tools.py index 8c5b6a4..055af36 100644 --- a/bot/modules/tools.py +++ b/bot/modules/tools.py @@ -1,7 +1,7 @@ import time import discord -from bot import traductions as tr +import traductions as tr class MainClass: diff --git a/main.py b/main.py index 436dc7a..21cf92a 100644 --- a/main.py +++ b/main.py @@ -76,7 +76,7 @@ foBot = FoBot(db_connection=db_connection) foWeb = FoWeb(bot=None, db=db_connection) -bot_app = foBot.start(os.environ['DISCORD_TOKEN'], max_messages=100000000) +bot_app = foBot.start(os.environ['FOBOT_DISCORD_TOKEN'], max_messages=100000000) bot_task = asyncio.ensure_future(bot_app) foWeb.listen(port=8888)