Veyra - Reaction Farm

Auto farm reactions with stamina/farm HUD

目前為 2025-09-18 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Veyra - Reaction Farm
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Auto farm reactions with stamina/farm HUD
// @match        https://demonicscans.org/title/*/chapter/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=demonicscans.org
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let isPaused = false;
    let scriptStopped = false;

    // --- HUD Setup ---
    const hud = document.createElement("div");
    hud.style.position = "fixed";
    hud.style.bottom = "10px";
    hud.style.right = "10px";
    hud.style.background = "rgba(0,0,0,0.8)";
    hud.style.color = "lime";
    hud.style.fontSize = "14px";
    hud.style.fontFamily = "monospace";
    hud.style.padding = "8px 12px";
    hud.style.borderRadius = "8px";
    hud.style.zIndex = "99999";
    hud.style.lineHeight = "1.5em";
    hud.innerHTML = `
        <div id="hud-status">⏳ Loading...</div>
        <button id="hud-toggle" style="
            margin-top:6px;
            padding:4px 8px;
            font-size:12px;
            border:none;
            border-radius:5px;
            cursor:pointer;
        ">⏸ Pause</button>
    `;
    document.body.appendChild(hud);

    const statusEl = document.getElementById("hud-status");
    const toggleBtn = document.getElementById("hud-toggle");

    toggleBtn.addEventListener("click", () => {
        isPaused = !isPaused;
        toggleBtn.textContent = isPaused ? "▶ Resume" : "⏸ Pause";
        hud.style.color = isPaused ? "yellow" : "lime";
    });

    function getStamina() {
        let staminaEl = document.evaluate(
            '//*[@id="discuscontainer"]/div[1]/div[1]/div[2]/span[1]/span',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        if (!staminaEl) return null;
        let [current, max] = staminaEl.innerText.split('/').map(s => parseInt(s.trim()));
        return { current, max };
    }

    function getFarm() {
        let farmEl = document.evaluate(
            '//*[@id="discuscontainer"]/div[1]/div[1]/div[2]/span[2]/span',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        if (!farmEl) return null;
        let [current, max] = farmEl.innerText.split('/').map(s => parseInt(s.trim()));
        return { current, max };
    }

    function updateHUD() {
        let staminaEl = document.evaluate(
            '//*[@id="discuscontainer"]/div[1]/div[1]/div[2]/span[1]/span',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
        ).singleNodeValue;

        let farmEl = document.evaluate(
            '//*[@id="discuscontainer"]/div[1]/div[1]/div[2]/span[2]/span',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
        ).singleNodeValue;

        let staminaText = staminaEl ? staminaEl.innerText.trim() : "0/0";
        let farmText = farmEl ? farmEl.innerText.trim() : "0/0";

        statusEl.innerText = `⚡ Stamina: ${staminaText}\n🌾 Farm: ${farmText}`;
    }

    function checkLimits() {
        let stamina = getStamina();
        let farm = getFarm();
        if (!stamina || !farm) return false;

        if (isPaused) {
            console.log("⏸️ Manually paused");
            return false;
        }

        if (stamina.max - stamina.current <= 30) {
            console.log("⏸️ Paused: stamina near limit (" + stamina.current + "/" + stamina.max + ")");
            hud.style.color = "orange";
            return false;
        }

        if (farm.current >= farm.max) {
            console.log("⏸️ Paused: farm limit reached (" + farm.current + "/" + farm.max + ")");
            hud.style.color = "red";
            scriptStopped = true;
            return false;
        }

        hud.style.color = "lime";
        return true;
    }

    function clickReaction() {
        let reaction = document.evaluate(
            '/html/body/div[5]/center/div/div[1]/div[3]/div[1]',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

        if (reaction) {
            reaction.scrollIntoView();
            reaction.click();
            console.log("✅ Clicked reaction on " + window.location.href);
        } else {
            console.log("⚠️ Reaction not found on " + window.location.href);
        }
    }

    function goNextPage() {
        let nextBtn = document.evaluate(
            '/html/body/div[5]/div[10]/div[1]/a[2]/span',
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

        if (nextBtn) {
            nextBtn.click();
        } else {
            console.log("❌ Next button not found, stopping.");
        }
    }

    function run() {
        updateHUD();

        if (!checkLimits()) {
            if (scriptStopped) return;
            setTimeout(run, 5000); // re-check later
            return;
        }


        clickReaction();
        setTimeout(goNextPage, 1500);
    }

    window.addEventListener('load', () => {
        setTimeout(run, 2000);
    });

})();