Outdated Idle MMO Battle Automation with GUI and Logs

Automatically clicks "Start Hunt" and "Battle Max" based on game conditions. Includes a GUI for toggling settings, viewing logs, and copying the log, with customizable cooldown and randomization to prevent bans.

当前为 2024-08-26 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Outdated Idle MMO Battle Automation with GUI and Logs
// @namespace     https://web.idle-mmo.com/
// @version       1.2
// @description  Automatically clicks "Start Hunt" and "Battle Max" based on game conditions. Includes a GUI for toggling settings, viewing logs, and copying the log, with customizable cooldown and randomization to prevent bans.
// @author       Unknown Monkey
// @match        https://web.idle-mmo.com/battle
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // Settings
    let autoBattleEnabled = true;
    let autoHuntEnabled = true;
    let cooldownMin = 2000; // Minimum cooldown (milliseconds)
    let cooldownMax = 5000; // Maximum cooldown (milliseconds)
    let randomizeCooldown = true;

    // Function to click buttons by XPath (enhanced with direct click method)
    function clickButtonByXPath(xpath) {
        setTimeout(() => {
            const button = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
            if (button) {
                // Check button state before clicking
                const isButtonDisabled = button.hasAttribute('disabled') || button.classList.contains('disabled');
                logMessage(`Button found with XPath: ${xpath}`);
                logMessage(`Button disabled state: ${isButtonDisabled}`);

                if (!isButtonDisabled) {
                    try {
                        button.click(); // Use click() directly
                        logMessage(`Clicked button with XPath: ${xpath}`);
                    } catch (error) {
                        logMessage(`Error clicking button with XPath: ${xpath} - ${error.message}`);
                    }
                } else {
                    logMessage(`Button with XPath: ${xpath} is disabled`);
                }
            } else {
                logMessage(`Button with XPath: ${xpath} not found`);
            }
        }, randomizeCooldown ? getRandomCooldown() : cooldownMin);
    }

    // Function to get the value of an element by CSS selector
    function getValueBySelector(selector) {
        const element = document.querySelector(selector);
        return element ? element.textContent.trim() : null;
    }

    // Function to get a random cooldown value within the specified range
    function getRandomCooldown() {
        return Math.floor(Math.random() * (cooldownMax - cooldownMin + 1)) + cooldownMin;
    }

    // Function to check if an element exists by XPath
    function elementExistsByXPath(xpath) {
        const element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        return element !== null;
    }

    // Function to check for the "Start Hunt" button
    function checkForStartHunt() {
        const startHuntXPath = '/html/body/div[1]/main/div[1]/div/div[2]/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div/div/div[1]/button';
        return elementExistsByXPath(startHuntXPath);
    }

    // Logging function
    function logMessage(message) {
        const logArea = document.getElementById('logArea');
        const timestamp = new Date().toLocaleTimeString();
        logArea.value += `[${timestamp}] ${message}\n`;
        logArea.scrollTop = logArea.scrollHeight;
    }

    // Automation logic (removed "Hunt Again" and only focuses on "Start Hunt" and "Battle Max")
    function automateBattle() {
        if (!autoBattleEnabled) return;

        // Updated XPaths and CSS selectors
        const battleMaxXPath = '/html/body/div[1]/main/div[1]/div/div[2]/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div[2]/div[1]/button';
        const battleMaxValueSelector = 'div.w-5'; // CSS selector for Battle Max Value
        const startHuntXPath = '/html/body/div[1]/main/div[1]/div/div[2]/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div/div/div[1]/button';
        const enemiesXPath = '/html/body/div[1]/main/div[1]/div/div[2]/div[2]/div/div[2]/div[1]/div[1]/div[2]/div';

        setTimeout(() => {
            // Re-evaluate the XPath to handle potential stale element reference
            const battleMaxButton = document.evaluate(battleMaxXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
            const battleMaxValue = getValueBySelector(battleMaxValueSelector);
            const startHuntButton = document.evaluate(startHuntXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

            // Check if there are any enemy buttons within the enemiesXPath container
            const enemiesContainer = document.evaluate(enemiesXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
            const enemyButtons = enemiesContainer ? enemiesContainer.querySelectorAll('button') : [];
            const enemiesExist = enemyButtons.length > 0;

            // Enhanced logging for debugging
            console.log("autoBattleEnabled:", autoBattleEnabled);
            console.log("battleMaxButton:", battleMaxButton);
            console.log("battleMaxButton.disabled:", battleMaxButton ? battleMaxButton.disabled : "null");
            console.log("battleMaxValue:", battleMaxValue);
            console.log("parseInt(battleMaxValue) > 0:", parseInt(battleMaxValue) > 0);
            console.log("startHuntButton:", startHuntButton);

            logMessage(`Enemies Exist: ${enemiesExist}`);
            logMessage(`Battle Max Value: ${battleMaxValue}`);

            // Prioritize "Start Hunt", then "Battle Max"
            if (autoBattleEnabled && startHuntButton) {
                logMessage(`Attempting to click "Start Hunt"`);
                clickButtonByXPath(startHuntXPath);
            } else if (autoBattleEnabled &&
                       battleMaxButton &&
                       !battleMaxButton.disabled &&
                       battleMaxValue !== null &&
                       parseInt(battleMaxValue) > 0) {
                logMessage(`Attempting to click "Battle Max"`);
                clickButtonByXPath(battleMaxXPath);
            } else {
                // Log specific reasons for not clicking
                if (!autoBattleEnabled) logMessage("Auto Battle is disabled.");
                if (!battleMaxButton) logMessage("Battle Max button not found.");
                if (battleMaxButton && battleMaxButton.disabled) logMessage("Battle Max button is disabled.");
                if (battleMaxValue === null) logMessage("Battle Max value is null.");
                if (!(parseInt(battleMaxValue) > 0)) logMessage("Battle Max value is not greater than 0.");
                if (!startHuntButton) logMessage("Start Hunt button not found.");
            }
        }, 500);
    }

    // Set up an interval for automation
    setInterval(automateBattle, randomizeCooldown ? getRandomCooldown() : cooldownMin);

    // GUI creation with a toggle button
    function createGUI() {
        // Create GUI container
        const gui = document.createElement('div');
        gui.id = 'battle-automation-gui';
        gui.innerHTML = `
            <div>
                <h3>Battle Automation</h3>
                <label><input type="checkbox" id="toggleAutoBattle" checked> Auto Battle</label><br>
                <label for="cooldownMin">Cooldown Min (ms):</label>
                <input type="number" id="cooldownMin" value="${cooldownMin}" min="0"><br>
                <label for="cooldownMax">Cooldown Max (ms):</label>
                <input type="number" id="cooldownMax" value="${cooldownMax}" min="0"><br>
                <label><input type="checkbox" id="toggleRandomizeCooldown" checked> Randomize Cooldown</label><br>
                <textarea id="logArea" rows="10" cols="40" readonly></textarea><br>
                <button id="copyLogButton">Copy Log</button><br>
            </div>
        `;
        document.body.appendChild(gui);

        // Create Show/Hide GUI button
        const toggleGUIButton = document.createElement('button');
        toggleGUIButton.id = 'toggleGUIButton';
        toggleGUIButton.textContent = 'Hide GUI';
        toggleGUIButton.style.position = 'fixed';
        toggleGUIButton.style.top = '10px';
        toggleGUIButton.style.right = '10px';
        toggleGUIButton.style.zIndex = '1001'; // Above GUI
        document.body.appendChild(toggleGUIButton);

        // Event listeners for toggling settings
        document.getElementById('toggleAutoBattle').addEventListener('change', (e) => {
            autoBattleEnabled = e.target.checked;
            logMessage(`Auto Battle: ${autoBattleEnabled}`);
        });

        // Event listeners for cooldown settings
        document.getElementById('cooldownMin').addEventListener('change', (e) => {
            cooldownMin = parseInt(e.target.value, 10);
            logMessage(`Cooldown Min set to: ${cooldownMin}`);
        });
        document.getElementById('cooldownMax').addEventListener('change', (e) => {
            cooldownMax = parseInt(e.target.value, 10);
            logMessage(`Cooldown Max set to: ${cooldownMax}`);
        });

        // Event listeners for randomizing cooldown
        document.getElementById('toggleRandomizeCooldown').addEventListener('change', (e) => {
            randomizeCooldown = e.target.checked;
            logMessage(`Randomize Cooldown: ${randomizeCooldown}`);
        });

        // Event listener for copying logs
        document.getElementById('copyLogButton').addEventListener('click', () => {
            const logArea = document.getElementById('logArea');
            logArea.select();
            document.execCommand('copy');
            logMessage('Log copied to clipboard.');
        });

        // Event listener for hiding/showing GUI
        document.getElementById('toggleGUIButton').addEventListener('click', () => {
            const gui = document.getElementById('battle-automation-gui');
            if (gui.style.opacity === '0') {
                gui.style.opacity = '1';
                document.getElementById('toggleGUIButton').textContent = 'Hide GUI';
            } else {
                gui.style.opacity = '0';
                document.getElementById('toggleGUIButton').textContent = 'Show GUI';
            }
        });

        // Inject CSS for GUI
        GM_addStyle(`
            #battle-automation-gui {
                position: fixed;
                top: 10px;
                right: 10px;
                background: rgba(255, 255, 255, 0.5); /* Semi-transparent background */
                border: 1px solid #ccc;
                padding: 10px;
                z-index: 1000;
                font-family: Arial, sans-serif;
                opacity: 1; /* Start with GUI visible */
                transition: opacity 0.3s ease; /* Smooth transition for hiding/showing */
            }
            #battle-automation-gui h3 {
                margin: 0;
                font-size: 16px;
                color: black;
            }
            #battle-automation-gui label,
            #battle-automation-gui input,
            #battle-automation-gui textarea,
            #battle-automation-gui button {
                font-size: 14px;
                color: black;
            }
            #logArea {
                color: red; /* Red text for the log area */
            }
        `);
    }

    // Create GUI on page load
    window.addEventListener('load', createGUI);
})();