Git游戏

您现在的位置是:首页 > 攻略大全 > 辅助脚本

辅助脚本

一万亿次免费抽卡加速和自动化

2025-07-09 辅助脚本1102
注:改变倍速会产生bug// ==UserScript==// @name 一万亿次免费抽卡加速和自动化 One Trillion Free Draws Accelerator and Automation// @namespace xfdz.OTFDAA// @version 2.0// @description 同时提供用户...

注:改变倍速会产生bug

// ==UserScript==

// @name         一万亿次免费抽卡加速和自动化 One Trillion Free Draws Accelerator and Automation

// @namespace    xfdz.OTFDAA

// @version      2.0

// @description  同时提供用户控制界面

// @author       Zero(加速), 销锋镝铸(自动化)

// @match        https://duducat.moe/gacha/*

// @match        https://gityxs.github.io/one-trillion-free-draws/*

// @grant        none

// @run-at       document-end

// @license      MIT

// ==/UserScript==


(function () {

    "use strict";

    const defaultOptions = {

        speedMultiplier: 1,

        autoDraw: {

            enabled: false,

            drawOnFull: false

        },

        autoSkill: {

            enabled: false,

            skills: {

                fire: false,

                water: false,

                leaf: false,

                sun: false,

                moon: false

            }

        }

    };

    let options = {};


    let interval = null;

    const intervalActions = new Map();


    let accelerator = null;

    let autoDrawManager = null;

    let autoSkillManager = null;

    let uiManager = null;


    function initialize() {

        try {

            let optionsInLocalStorage = JSON.parse(window.localStorage.getItem("OTFDAAOptions"));

            if (optionsInLocalStorage) {

                try{

                    options = Object.assign({}, defaultOptions, optionsInLocalStorage);

                    console.log("[OTFDAA] 设置已从本地存储中加载");

                }

                catch{

                    options = defaultOptions;

                    console.log("[OTFDAA] 本地存储中的设置存在问题,已初始化设置");

                }

            }

            else {

                options = defaultOptions;

                saveOptions();

                console.log("[OTFDAA] 未找到设置,已初始化设置");

            }

        }

        catch (e) {

            options = defaultOptions;

            console.log("[OTFDAA] 未找到设置,已初始化设置");

        }

        accelerator = new Accelerator();

        autoDrawManager = new AutoDrawManager();

        autoSkillManager = new AutoSkillManager();

        uiManager = new UIManager();

        interval = setInterval(() => {

            for (let action of intervalActions.values()) {

                action();

            }

        }, 500);

        window.addEventListener("beforeunload", () => {

            accelerator.restoreOriginalAPIs();

            clearInterval(interval);

        });

    }


    function saveOptions() {

        window.localStorage.setItem("OTFDAAOptions", JSON.stringify(options));

    }


    class Accelerator {

        originalAPIs;

        performanceNowOverridden = false;

        requestAnimationFrameOverridden = false;

        syncTimeSourcesOverridden = false;


        constructor() {

            this.originalAPIs = {

                raf: window.requestAnimationFrame.bind(window),

                performanceNow: performance.now.bind(performance),

                DateNow: Date.now

            };

            try {

                this.initialize();

                console.log("[OTFDAA] 加速OTFDAA已激活");

            }

            catch (error) {

                console.error("[OTFDAA] 初始化失败:", error);

                setTimeout(this.initialize, 1500); // 重试初始化

            }

        }


        initialize() {

            this.overridePerformanceNow();

            this.overrideRequestAnimationFrame();

            this.syncTimeSources();

        }


        setSpeedMultiplier(multiplier) {

            options.speedMultiplier = multiplier;

            console.log(`[OTFDAA] 已修改游戏速度为 ×${options.speedMultiplier}`);

            saveOptions();

        }


        // 劫持 performance.now

        overridePerformanceNow() {

            if (this.performanceNowOverridden) {

                return;

            }

            Object.defineProperty(performance, "now", {

                value: () => this.originalAPIs.performanceNow() * options.speedMultiplier,

                configurable: true,

                writable: false

            });

            console.log("[OTFDAA] performance.now 已劫持");

            this.performanceNowOverridden = true;

        }


        // 劫持 requestAnimationFrame

        overrideRequestAnimationFrame() {

            if (this.requestAnimationFrameOverridden) {

                return;

            }

            window.requestAnimationFrame = (callback) => {

                return this.originalAPIs.raf((timestamp) => {

                    callback(timestamp * options.speedMultiplier);

                });

            };

            console.log("[OTFDAA] requestAnimationFrame 已劫持");

            this.requestAnimationFrameOverridden = true;

        }


        // 同步时间源

        syncTimeSources() {

            if (this.syncTimeSourcesOverridden) {

                return;

            }

            const baseTime = Date.now();

            Date.now = () => baseTime + (performance.now() - baseTime);

            console.log("[OTFDAA] 时间源已同步");

            this.syncTimeSourcesOverridden = true;

        }


        // 恢复原始 API

        restoreOriginalAPIs() {

            Object.defineProperty(performance, "now", {

                value: this.originalAPIs.performanceNow,

                configurable: true

            });

            window.requestAnimationFrame = this.originalAPIs.raf;

            Date.now = this.originalAPIs.DateNow;

            console.log("[OTFDAA] 原始 API 已恢复");

            this.performanceNowOverridden = false;

            this.requestAnimationFrameOverridden = false;

            this.syncTimeSourcesOverridden = false;

        }

    }


    class AutoDrawManager {


        constructor() {

            this.setAutoDraw(options.autoDraw.enabled, false);

        }


        setAutoDraw(on, save = true) {

            options.autoDraw.enabled = on;

            if (on) {

                if (!intervalActions.has("autoDraw")) {

                    intervalActions.set("autoDraw", this.draw);

                }

            }

            else {

                intervalActions.delete("autoDraw");

            }

            if (save) {

                saveOptions();

            }

        }


        draw() {

            try {

                const drawButton = options.autoDraw.drawOnFull ?

                    document.querySelector("#draw-zone > .currency.f-fire")

                        ?.parentElement

                        ?.querySelector("#draw-button") :

                    document.querySelector("#draw-button");

                if (drawButton) {

                    drawButton.click();

                }

                const cancelButton = document.querySelector(

                    ".card-list.done + .draw-result > button");

                if (cancelButton) {

                    cancelButton.click();

                }

            }

            catch {

            }

        }


        setDrawOnFull(on) {

            options.autoDraw.drawOnFull = on;

            saveOptions();

        }

    }


    class AutoSkillManager {

        constructor() {

            this.setAutoSkillEnabled(options.autoSkill.enabled, false);

        }


        setAutoSkillEnabled(on, save = true) {

            options.autoSkill.enabled = on;

            if (on) {

                if (!intervalActions.has("autoSkill")) {

                    intervalActions.set("autoSkill", this.useSkill);

                }

            }

            else {

                intervalActions.delete("autoSkill");

            }

            if (save) {

                saveOptions();

            }

        }


        useSkill() {

            if (!options.autoSkill.enabled) {

                return;

            }

            const skillHolder = document.querySelector("#draw-options .skill-holder");

            if (!skillHolder) {

                return;

            }

            const skillButtons = skillHolder.children;

            for (let i = 0; i < 5; i++) {

                let skillButton = skillButtons[i];

                if (skillButton.classList.contains("disabled")) {

                    continue;

                }

                for (const [skill, on] of Object.entries(options.autoSkill.skills)) {

                    if (on) {

                        const button = skillHolder.querySelector(`.f-${skill}:not(.disabled)`);

                        if (button) {

                            button.click();

                        }

                    }

                }

            }

        }


        setAutoSkill(skill, on) {

            switch (skill) {

                case "fire":

                    options.autoSkill.skills.fire = on;

                    break;

                case "water":

                    options.autoSkill.skills.water = on;

                    break;

                case "leaf":

                    options.autoSkill.skills.leaf = on;

                    break;

                case "sun":

                    options.autoSkill.skills.sun = on;

                    break;

                case "moon":

                    options.autoSkill.skills.moon = on;

                    break;

            }

            saveOptions();

        }

    }


    class UIManager {

        constructor() {

            this.insertStyle();

            this.createControlPanel();

        }


        insertStyle() {

            const style = document.createElement("style");

            style.textContent = `

#OTFDAAControlPanel {

    display: flex;

    flex-direction: column;

    gap: 8px;

    position: fixed;

    bottom: 40px;

    left: 25px;

    max-width: 248px;

    z-index: 2000001;

}

#OTFDAAControlPanel .OTFDAAOptionContainer {

    display: flex;

    gap: 12px;

    justify-content: space-between;

    align-items: center;

    min-height: 35px;

}

#OTFDAASkillPanel {

    display: flex;

    gap: 2px;

}

#OTFDAASkillPanel button{

    flex: 1;

    aspect-ratio: 1;

}`;

            document.head.appendChild(style);

        }


        createControlPanel() {

            if (document.getElementById("OTFDAAControlPanel")) {

                return;

            }

            const panelContainer = document.createElement("div");

            panelContainer.id = "OTFDAAControlPanel";

            panelContainer.classList.add("opt-container");

            const panelTitle = document.createElement("h3");

            panelTitle.textContent = "OTFDAA 控制台";

            panelTitle.style.marginTop = "10px";

            panelContainer.appendChild(panelTitle);

            this.createCheckbox("自动抽卡", panelContainer, options.autoDraw.enabled, event => {

                autoDrawManager.setAutoDraw(event.target.checked);

            });

            this.createCheckbox("等待批量能量达到上限",

                panelContainer,

                options.autoDraw.drawOnFull,

                event => {

                    autoDrawManager.setDrawOnFull(event.target.checked);

                });

            this.createCheckbox("自动技能", panelContainer, options.autoSkill.enabled, event => {

                autoSkillManager.setAutoSkillEnabled(event.target.checked);

                const skillPanel = document.getElementById("OTFDAASkillPanel");

                if (skillPanel) {

                    skillPanel.style.display = event.target.checked ? "flex" : "none";

                }

            });

            this.createNumberInput("加速倍率",

                panelContainer,

                0.1,

                100,

                0.1,

                options.speedMultiplier,

                event => {

                    let num = event.target.valueAsNumber;

                    if (num < 0.1) {

                        num = 0.1;

                        event.target.value = num;

                    }

                    if (num > 100) {

                        num = 100;

                        event.target.value = num;

                    }

                    accelerator.setSpeedMultiplier(num);

                });

            document.body.appendChild(panelContainer);

            this.createSkillButtons();

        }


        createCheckbox(title, parent, checked, onChange) {

            const container = document.createElement("div");

            container.classList.add("OTFDAAOptionContainer");

            const titleLabel = document.createElement("label");

            titleLabel.textContent = title;

            titleLabel.htmlFor = title;

            const checkbox = document.createElement("input");

            checkbox.type = "checkbox";

            checkbox.id = title;

            checkbox.checked = checked;

            checkbox.addEventListener("change", onChange);

            container.appendChild(titleLabel);

            container.appendChild(checkbox);

            parent.appendChild(container);

        }


        createNumberInput(title, parent, min, max, step, value, onChange) {

            const container = document.createElement("div");

            container.classList.add("OTFDAAOptionContainer");

            const titleLabel = document.createElement("label");

            titleLabel.textContent = title;

            titleLabel.htmlFor = title;

            const input = document.createElement("input");

            input.type = "number";

            input.id = title;

            input.min = min;

            input.max = max;

            input.step = step;

            input.value = value;

            input.addEventListener("change", onChange);

            container.appendChild(titleLabel);

            container.appendChild(input);

            parent.appendChild(container);

        }


        createSlider(title, parent, min, max, step, value, onChange) {

            const container = document.createElement("div");

            container.classList.add("OTFDAAOptionContainer");

            const titleSpan = document.createElement("span");

            titleSpan.textContent = title;

            const sliderContainer = document.createElement("div");

            const sliderInput = document.createElement("input");

            sliderInput.type = "range";

            sliderInput.id = title;

            sliderInput.min = min;

            sliderInput.max = max;

            sliderInput.step = step;

            sliderInput.value = value;

            sliderInput.style.width = "140px";

            const sliderLabel = document.createElement("label");

            sliderLabel.textContent = value.toFixed(1);

            sliderLabel.htmlFor = title;

            sliderInput.addEventListener("change", event => {

                sliderLabel.textContent = "×" + sliderInput.valueAsNumber.toFixed(1);

                onChange(event);

            });

            sliderContainer.appendChild(sliderLabel);

            sliderContainer.appendChild(sliderInput);

            container.appendChild(titleSpan);

            container.appendChild(sliderContainer);

            parent.appendChild(container);

        }


        createSkillButtons() {

            if (document.getElementById("OTFDAASkillPanel")) {

                return;

            }

            const skillHolder = document.querySelector("#draw-options .skill-holder");

            if (!skillHolder) {

                return;

            }

            const container = document.createElement("div");

            container.style.display = options.autoSkill.enabled ? "flex" : "none";

            container.id = "OTFDAASkillPanel";

            for (const [skill, on] of Object.entries(options.autoSkill.skills)) {

                const button = document.createElement("button");

                button.classList.add(`f-${skill}`);

                button.disabled = true;

                const checkbox = document.createElement("input");

                checkbox.type = "checkbox";

                checkbox.checked = on;

                checkbox.addEventListener("change", event => {

                    autoSkillManager.setAutoSkill(skill, event.target.checked);

                });

                button.appendChild(checkbox);

                container.appendChild(button);

            }

            skillHolder.after(container);

        }

    }


    if (!window.OTFDAALoaded) {

        window.OTFDAALoaded = true;

        if (document.readyState === "complete") {

            initialize();

        }

        else {

            window.addEventListener("load", () => {

                initialize();

            });

        }

    }

})();


文章评论

共有0条评论来说两句吧...