IC Auto Crafter

Automatically craft by inputting a lineage.

当前为 2025-01-19 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         IC Auto Crafter
// @namespace    http://tampermonkey.net/
// @version      1.5
// @license      MIT
// @description  Automatically craft by inputting a lineage.
// @icon         https://i.imgur.com/WlkWOkU.png
// @author       @activetutorial on discord
// @match        https://neal.fun/infinite-craft/
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
    "use strict";

    (window.AT ||= {}).autocrafterdata = {
        iconthing: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIGZpbGw9IiMwMDAwMDAiIHZlcnNpb249IjEuMSIgaWQ9IkNhcGFfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgDQoJIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDQ1LjM2MyA0NS4zNjMiDQoJIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQoJPGc+DQoJCTxwYXRoIGQ9Ik0xLjc4OCwxNi45NDVjMC4zODgsMC4zODUsMC45MTMsMC42MDEsMS40NTksMC42MDFsMjcuNDkzLTAuMDM1djMuODMxYzAuMDAzLDAuODM2LDAuNTU2LDEuNTg2LDEuMzI5LDEuOTA0DQoJCQljMC43NzEsMC4zMTQsMS42NTgsMC4xMzUsMi4yNDYtMC40NTlsOS4wOTEtOS4xOGMxLjA2Mi0xLjA3MSwxLjA2LTIuODAxLTAuMDA5LTMuODY4bC05LjEzNy05LjEzNA0KCQkJYy0wLjU5LTAuNTkxLTEuNDc5LTAuNzY4LTIuMjUtMC40NDZjLTAuNzcsMC4zMTktMS4yNzEsMS4wNzQtMS4yNywxLjkwOEwzMC43NCw1LjlMMy4yMTksNS45MzcNCgkJCUMyLjA4LDUuOTQsMS4xNjEsNi44NjQsMS4xNjMsOC4wMDRsMC4wMTgsNy40ODNDMS4xODIsMTYuMDM0LDEuNDAxLDE2LjU2LDEuNzg4LDE2Ljk0NXoiLz4NCgkJPHBhdGggZD0iTTQyLjE0NiwyNy45MDFsLTI3LjUyMi0wLjAzNWwtMC4wMDEtMy44MzRjMC4wMDItMC44MzUtMC41LTEuNTg3LTEuMjctMS45MDdjLTAuNzcxLTAuMzIxLTEuNjYtMC4xNDYtMi4yNSwwLjQ0NQ0KCQkJbC05LjEzNiw5LjEzNWMtMS4wNjcsMS4wNjQtMS4wNzEsMi43OTYtMC4wMDksMy44NjZsOS4wOSw5LjE4MWMwLjU4OCwwLjU5NiwxLjQ3NSwwLjc3MiwyLjI0NywwLjQ1OA0KCQkJYzAuNzcyLTAuMzE2LDEuMzI2LTEuMDY2LDEuMzI5LTEuOTA0di0zLjgzbDI3LjQ5MywwLjAzNWMwLjU0NywwLDEuMDcyLTAuMjE2LDEuNDU5LTAuNjAyczAuNjA1LTAuOTEsMC42MDctMS40NTZMNDQuMiwyOS45Nw0KCQkJQzQ0LjIwMywyOC44Myw0My4yODQsMjcuOTAzLDQyLjE0NiwyNy45MDF6Ii8+DQoJPC9nPg0KPC9nPg0KPC9zdmc+",
        infinitecraft: null,
        autocraftButton: null,
        anticheat: true,
        saveInfo: true, // Stores how you crafted something
        isCrafting: false,
        popupHTML: `
            <style>
                body {
                    margin: 0;
                    font-family: Arial, sans-serif;
                    background-color: #1e1e1e;
                    color: #f0f0f0;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    justify-content: center;
                    height: 100%;
                }
                textarea {
                    width: 90%;
                    height: 100px;
                    margin-bottom: 10px;
                    background-color: #2d2d2d;
                    color: #f0f0f0;
                    border: 1px solid #555;
                    border-radius: 5px;
                    padding: 10px;
                }
                label {
                    font-size: 14px;
                }
                input[type="checkbox"] {
                    margin-right: 5px;
                }
                hr {
                    width: 90%;
                    border: none;
                    border-top: 1px solid #555;
                    margin: 15px 0;
                }
                .highlight {
                    font-weight: bold;
                    color: #ffffff; /* Plain white */
                    margin-bottom: 20px; /* Increased spacing */
                }
                button {
                    color: #ffffff; /* White text */
                    font-weight: bold;
                    text-shadow: 1px 1px 2px #000000; /* Black outline for text */
                    border: none;
                    border-radius: 5px;
                    padding: 10px 20px;
                    cursor: pointer;
                    font-size: 16px;
                    margin-top: 20px; /* Increased spacing */
                }
                button#submitButton {
                    background-color: #4caf50;
                }
                button#submitButton:hover {
                    filter: brightness(0.9);
                }
                button#autoCraftButton {
                    background-color: #d4b106;
                }
                button#autoCraftButton:hover {
                    filter: brightness(0.9);
                }
            </style>
            <textarea id="userInput" placeholder="Enter your lineage..."></textarea>
            <button id="submitButton">Craft</button>
            <hr>
            <div class="highlight">Cheating section:</div>
            <label>
                <input type="checkbox" id="anticheatToggle" checked> Enable Anti-Cheat
            </label>
            <button id="autoCraftButton"></button>`,
        processLineage: async function () {
            const userInput = await this.getUserInput();
            if (typeof userInput.autoCraft === "boolean"){
                console.log("Auto craft started/stopped", this.isCrafting);
                this.craftSomething();
                return;
            }
            const { lineage, anticheatEnabled } = userInput;
            this.anticheat = anticheatEnabled; // Update anticheat option
            const recipes = this.parseRecipes(lineage);

            for (let i = 0; i < recipes.length; i++) {
                const [string1, string2] = recipes[i];
                // Anti cheat
                const element1Exists = this.infinitecraft.elements.some(el => el.text?.toLowerCase() === string1?.toLowerCase());
                const element2Exists = this.infinitecraft.elements.some(el => el.text?.toLowerCase() === string2?.toLowerCase());
                if (!this.anticheat || (element1Exists && element2Exists)) {
                    await this.infinitecraft.craft({text: string1}, {text: string2});
                    this.saveInfo && (this.infinitecraft.elements.at(-1).autocraft = (
                        (element1Exists && element2Exists) ? "lineage" : "cheatlineage") // add craft info
                    );
                    this.infinitecraft.instances.pop();
                } else {
                    await this.showToast(`Skipping craft: You don"t have one of these elements: "${string1}", "${string2}"`);
                }
            }
        },
        parseRecipes: function (lineage) {
            const recipes = [];
            const lines = lineage.split("\n").map(line => line.trim());
            const isNumberedLineage = lines[0].match(/^\d+\.\s*/);

            lines.forEach(line => {
                if (!line || !line.includes(" = ")) return;

                if (isNumberedLineage) {
                    line = line.replace(/^\d+\.\s*/, ""); // Account for numbered lineages
                }

                const [ingredients, result] = line.split(" = ");
                if (!ingredients || !result) return;
                const ingredientList = ingredients.trim().split(" + ");
                if (ingredientList.length < 2) return;
                recipes.push(ingredientList.map(ingredient => ingredient.trim()));
            });

            return recipes;
        },
        craftSomething: async function () { // randomly craft 2 items
            while (this.isCrafting) {
                await this.infinitecraft.craft({
                    text: this.infinitecraft.elements.at(this.infinitecraft.elements.length * Math.random()).text
                }, {
                    text: this.infinitecraft.elements.at(this.infinitecraft.elements.length * Math.random()).text
                });
                this.saveInfo && (this.infinitecraft.elements.at(-1).autocraft = "random"); // set craft info
                this.infinitecraft.instances = [];
                await new Promise(resolve => setTimeout(resolve, 200));
            }
        },
        getUserInput: async function () {
            return new Promise((resolve) => {
                const screenWidth = window.screen.width;
                const screenHeight = window.screen.height;
                const popupWidth = 400;
                const popupHeight = 350;
                const left = (screenWidth - popupWidth) / 2;
                const top = (screenHeight - popupHeight) / 2;
                let popup = window.open("", "", `width=${popupWidth},height=${popupHeight},top=${top},left=${left}`);
                popup.document.write(this.popupHTML); // Open popup
                const autoCraftButton = popup.document.getElementById("autoCraftButton");
                if (this.isCrafting) { // Set auto craft button
                    autoCraftButton.textContent = "Stop Auto Craft";
                    autoCraftButton.style.backgroundColor = "#ff0000";
                } else {
                    autoCraftButton.textContent = "Start Auto Craft";
                    autoCraftButton.style.backgroundColor = "#d4b106";
                }
                autoCraftButton.addEventListener("click", () => {
                    this.isCrafting = !this.isCrafting;
                    popup.close();
                    resolve({ autoCraft: this.isCrafting });
                });
                popup.document.getElementById("submitButton").addEventListener("click", function () {
                    let userInput = popup.document.getElementById("userInput").value;
                    let anticheatEnabled = popup.document.getElementById("anticheatToggle").checked;
                    popup.close();
                    resolve({ lineage: userInput, anticheatEnabled: anticheatEnabled });
                });
            });
        },
        showToast: function(message) {
            const toast = document.createElement("div");
            toast.textContent = message;
            Object.assign(toast.style, {
                position: "fixed",
                left: "50%",
                transform: "translateX(-50%)",
                padding: "10px 20px",
                backgroundColor: "#333",
                color: "#fff",
                borderRadius: "5px",
                fontSize: "16px",
                opacity: "0",
                transition: "opacity 0.5s ease, bottom 0.3s ease",
                marginTop: "10px"
            });
            const existingToasts = document.querySelectorAll(".toast");
            const offset = existingToasts.length * (toast.offsetHeight + 40);
            toast.style.bottom = `${30 + offset}px`;
            toast.classList.add("toast");
            document.body.appendChild(toast);
            (async () => {
                await new Promise(resolve => setTimeout(resolve, 10));
                toast.style.opacity = "1";
                await new Promise(resolve => setTimeout(resolve, 3000));
                toast.style.opacity = "0";
                await new Promise(resolve => setTimeout(resolve, 500));
                toast.remove();
                const remainingToasts = document.querySelectorAll(".toast");
                remainingToasts.forEach((t, index) => {
                    t.style.bottom = `${30 + index * (toast.offsetHeight + 40)}px`;
                });
            })();
            return new Promise(resolve => setTimeout(resolve, 50)); // 0.05 delay
        },
        addUiOption: function () {
            this.autocraftButton = document.createElement("div");
            this.autocraftButton.classList.add("setting");
            this.autocraftButton.textContent = "Autocrafter";
            const img = document.createElement("img");
            img.src = this.iconthing;
            this.autocraftButton.appendChild(img);
            this.autocraftButton.onclick = function () {
                window.AT.autocrafterdata.processLineage();
            };

            document.querySelector(".settings-content").appendChild(this.autocraftButton);
            return true;
        },
        updateInstance: function (instance) {
            const element = this.infinitecraft.elements.find(
                (element) =>
                element.text.toLowerCase() === instance.text.toLowerCase()
            );
            element.autocraft &&
            instance.elem.setAttribute("autocraft", element.autocraft);
        },
        start: function () {
            if (document.querySelector(".settings-content")) { // Wait for IC Helper
                this.infinitecraft = document.querySelector(".container").__vue__;
                this.addUiOption();
                const setInstanceZIndex = this.infinitecraft.setInstanceZIndex;
                this.infinitecraft.setInstanceZIndex = ((instance, instanceID) => {
                    setTimeout(() => {
                        this.updateInstance(instance);
                    }, 0);
                    return setInstanceZIndex(instance, instanceID);
                });
            } else {
                setTimeout(this.start.bind(this), 200);
            }
        }
    };
    window.AT.autocrafterdata.start();

})();