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.

// ==UserScript==
// @name         Idle MMO Battle Automation with GUI and Logs
// @namespace    https://web.idle-mmo.com/
// @version      1.3
// @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
// @match        https://web.idle-mmo.com/battle?same_window=true
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

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

    // Function to log messages to the GUI
    function logMessage(message) {
        const logArea = document.getElementById('logArea');
        const timestamp = new Date().toLocaleTimeString();
        logArea.value += `[${timestamp}] ${message}\n`;
        logArea.scrollTop = logArea.scrollHeight; // Auto-scroll to the bottom
    }

    // Function to click buttons by CSS selector with improved timing
    function clickButtonBySelector(selector) {
        const waitForButton = setInterval(() => {
            const button = document.querySelector(selector);
            if (button) {
                const isButtonDisabled = button.hasAttribute('disabled') || button.classList.contains('opacity-40');
                logMessage(`Button found with selector: ${selector}`);
                logMessage(`Button disabled state: ${isButtonDisabled}`);
                if (!isButtonDisabled) {
                    try {
                        clearInterval(waitForButton);

                        // Introduce a small random delay before clicking to simulate more human-like behavior
                        setTimeout(() => {
                            button.click();
                            logMessage(`Clicked button with selector: ${selector}`);
                            // Log button action
                            logMessage(`Button ${selector} action triggered.`);
                        }, getRandomCooldown()); // Use a small random delay

                    } catch (error) {
                        logMessage(`Error clicking button with selector: ${selector} - ${error.message}`);
                    }
                } else {
                    logMessage(`Button with selector: ${selector} is disabled`);
                }
            } else {
                logMessage(`Button with selector: ${selector} not found`);
            }
        }, 1000); // Check every 1000ms
    }

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

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

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

        const battleMaxValueSelector = 'div.w-5'; // Adjust selector if necessary
        const startHuntSelector = 'button.bg-white\\/10:nth-child(1)';
        const battleMaxButtonSelector = 'button.battle-max'; // Placeholder selector for "Battle Max" button

        setTimeout(() => {
            const battleMaxValue = getValueBySelector(battleMaxValueSelector);
            logMessage(`Battle Max Value: ${battleMaxValue}`);

            if (document.querySelector(startHuntSelector)) {
                logMessage(`Attempting to click "Start Hunt"`);
                clickButtonBySelector(startHuntSelector);
            } else if (battleMaxValue > 0 && document.querySelector(battleMaxButtonSelector)) {
                logMessage(`Attempting to click "Battle Max" button`);
                clickButtonBySelector(battleMaxButtonSelector);
            } else {
                logMessage(`"Start Hunt" button not found or Battle Max value is not greater than 0, or "Battle Max" button not found.`);
            }
        }, randomizeCooldown ? getRandomCooldown() : cooldownMin);
    }

    // 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: #ffffff;
                border: 1px solid #cccccc;
                padding: 10px;
                border-radius: 5px;
                box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
                z-index: 1000;
                opacity: 1; /* Ensure GUI is initially visible */
                transition: opacity 0.3s; /* 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 button,
            #battle-automation-gui textarea {
                font-size: 14px;
                color: black;
            }
            #battle-automation-gui textarea {
                width: 100%;
                font-family: monospace;
            }
            #toggleGUIButton {
                background: #f39c12;
                color: white;
                border: none;
                padding: 8px 16px;
                cursor: pointer;
                z-index: 1001;
            }
        `);
    }

    // Initialize GUI
    createGUI();
})();