您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced auto farm reactions with comprehensive HUD and session management
// ==UserScript== // @name Veyra - Enhanced Reaction Farm // @namespace http://tampermonkey.net/ // @version 2.0.1 // @description Enhanced auto farm reactions with comprehensive HUD and session management // @match https://demonicscans.org/title/*/chapter/* // @match https://demonicscans.org/signin.php // @match https://demonicscans.org/index.php // @icon https://www.google.com/s2/favicons?sz=64&domain=demonicscans.org // @grant none // @license GNU General Public License v3.0 // @run-at document-end // ==/UserScript== (function() { 'use strict'; const AUTO_LOGIN_EMAIL = "YOUR_EMAIL_HERE"; // <-- Replace const AUTO_LOGIN_PASSWORD = "YOUR_PASSWORD_HERE"; // <-- Replace // Session state let farmingState = { isRunning: false, isPaused: false, mode: 'farmX', // 'farmX' or 'farmUntil' targetValue: 0, sessionProgress: 0, hasStartedThisSession: false }; // Load session state from localStorage function loadSessionState() { const saved = localStorage.getItem('veyra_farming_state'); if (saved) { const parsed = JSON.parse(saved); farmingState = { ...farmingState, ...parsed }; // Don't restore isRunning or isPaused - these reset on page load farmingState.isRunning = false; farmingState.isPaused = false; } } // Save session state to localStorage function saveSessionState() { localStorage.setItem('veyra_farming_state', JSON.stringify(farmingState)); } // --- HUD Setup --- function createHUD() { const hud = document.createElement("div"); hud.id = "veyra-hud"; hud.style.cssText = ` position: fixed; bottom: 10px; right: 10px; background: rgba(0,0,0,0.95); color: #00ff00; font-size: 12px; font-family: 'Courier New', monospace; padding: 12px; border-radius: 8px; border: 2px solid #00ff00; z-index: 99999; min-width: 280px; box-shadow: 0 4px 12px rgba(0,0,0,0.5); `; hud.innerHTML = ` <div style="text-align: center; margin-bottom: 8px; font-weight: bold; color: #ffff00;"> 🎯 VEYRA FARM v2.0 </div> <div id="stats-container" style="margin-bottom: 10px;"> <div>⚡ Stamina: <span id="stamina-display">Loading...</span></div> <div>📊 Daily: <span id="daily-display">Loading...</span></div> <div>🏆 Session: <span id="session-display">0</span></div> </div> <div id="mode-container" style="margin-bottom: 10px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 4px;"> <div style="margin-bottom: 6px;"> <label style="display: flex; align-items: center; cursor: pointer;"> <input type="radio" name="farmMode" value="farmX" id="mode-farmX" style="margin-right: 6px;"> <span>Farm X Stamina</span> </label> </div> <div style="margin-bottom: 6px;"> <label style="display: flex; align-items: center; cursor: pointer;"> <input type="radio" name="farmMode" value="farmUntil" id="mode-farmUntil" style="margin-right: 6px;"> <span>Farm Until X Stamina</span> </label> </div> <div style="margin-top: 6px;"> <label>Target Value:</label> <input type="number" id="target-input" value="0" min="0" style=" width: 60px; margin-left: 6px; padding: 2px 4px; background: rgba(0,0,0,0.5); color: #00ff00; border: 1px solid #00ff00; border-radius: 3px; "> </div> </div> <div id="controls-container" style="text-align: center;"> <button id="start-btn" style=" padding: 8px 16px; background: #00aa00; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold; font-size: 12px; ">▶ START FARMING</button> <div id="running-controls" style="display: none;"> <button id="pause-btn" style=" padding: 6px 12px; background: #ffaa00; color: white; border: none; border-radius: 5px; cursor: pointer; margin-right: 8px; font-size: 11px; ">⏸ PAUSE</button> <button id="stop-btn" style=" padding: 6px 12px; background: #aa0000; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 11px; ">⏹ STOP</button> </div> </div> <div id="status-display" style=" margin-top: 8px; text-align: center; font-size: 11px; color: #888; ">Ready to farm</div> `; document.body.appendChild(hud); setupHUDEvents(); restoreHUDState(); } function setupHUDEvents() { const startBtn = document.getElementById('start-btn'); const pauseBtn = document.getElementById('pause-btn'); const stopBtn = document.getElementById('stop-btn'); const modeRadios = document.querySelectorAll('input[name="farmMode"]'); const targetInput = document.getElementById('target-input'); startBtn.addEventListener('click', startFarming); pauseBtn.addEventListener('click', togglePause); stopBtn.addEventListener('click', stopFarming); modeRadios.forEach(radio => { radio.addEventListener('change', (e) => { farmingState.mode = e.target.value; saveSessionState(); }); }); targetInput.addEventListener('change', (e) => { farmingState.targetValue = parseInt(e.target.value) || 0; saveSessionState(); }); } function restoreHUDState() { // Restore mode selection document.getElementById(`mode-${farmingState.mode}`).checked = true; // Restore target value document.getElementById('target-input').value = farmingState.targetValue; // Update session display document.getElementById('session-display').textContent = farmingState.sessionProgress; // Show appropriate controls based on session state if (farmingState.hasStartedThisSession) { document.getElementById('start-btn').style.display = 'none'; document.getElementById('running-controls').style.display = 'block'; // Don't update status here - will be handled in initialize() } } // --- Data Extraction Functions --- 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.replace(/,/g,'').trim(), 10)); 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.replace(/,/g,'').trim(), 10)); return { current, max }; } function updateHUDDisplay() { const stamina = getStamina(); const farm = getFarm(); const staminaDisplay = stamina ? `${stamina.current}/${stamina.max}` : 'N/A'; const farmDisplay = farm ? `${farm.current}/${farm.max}` : 'N/A'; document.getElementById('stamina-display').textContent = staminaDisplay; document.getElementById('daily-display').textContent = farmDisplay; document.getElementById('session-display').textContent = farmingState.sessionProgress; } function updateStatus(message) { const statusEl = document.getElementById('status-display'); if (statusEl) { statusEl.textContent = message; } } // --- Farming Control Functions --- function startFarming() { farmingState.isRunning = true; farmingState.isPaused = false; farmingState.hasStartedThisSession = true; document.getElementById('start-btn').style.display = 'none'; document.getElementById('running-controls').style.display = 'block'; saveSessionState(); updateStatus('Starting farm...'); setTimeout(() => farmLoop(), 1000); } function togglePause() { const pauseBtn = document.getElementById('pause-btn'); farmingState.isPaused = !farmingState.isPaused; if (farmingState.isPaused) { pauseBtn.textContent = '▶ RESUME'; pauseBtn.style.background = '#00aa00'; updateStatus('Farming paused'); } else { pauseBtn.textContent = '⏸ PAUSE'; pauseBtn.style.background = '#ffaa00'; updateStatus('Farming resumed'); setTimeout(() => farmLoop(), 1000); } saveSessionState(); } function stopFarming() { farmingState.isRunning = false; farmingState.isPaused = false; farmingState.hasStartedThisSession = false; farmingState.sessionProgress = 0; document.getElementById('start-btn').style.display = 'block'; document.getElementById('running-controls').style.display = 'none'; document.getElementById('pause-btn').textContent = '⏸ PAUSE'; document.getElementById('pause-btn').style.background = '#ffaa00'; saveSessionState(); updateStatus('Farming stopped. Session reset.'); updateHUDDisplay(); } // --- Farming Logic --- function checkStopConditions() { const stamina = getStamina(); const farm = getFarm(); if (!stamina || !farm) { return { shouldStop: true, reason: 'Unable to read stamina/farm data' }; } // Condition A: Current Stamina >= (Max Stamina - 30) if (stamina.current >= (stamina.max - 30)) { return { shouldStop: true, reason: 'Stamina limit reached (max - 30)' }; } // Condition B: Current Daily Progress >= Max Daily Limit if (farm.current >= farm.max) { return { shouldStop: true, reason: 'Daily farm limit reached' }; } // Condition C: Farm X mode and has farmed X stamina if (farmingState.mode === 'farmX' && farmingState.targetValue > 0) { if (farmingState.sessionProgress >= farmingState.targetValue) { return { shouldStop: true, reason: `Target of ${farmingState.targetValue} stamina farmed` }; } } // Condition D: Farm Until X mode and current stamina >= X if (farmingState.mode === 'farmUntil' && farmingState.targetValue > 0) { if (stamina.current >= farmingState.targetValue) { return { shouldStop: true, reason: `Target stamina of ${farmingState.targetValue} reached` }; } } return { shouldStop: false }; } 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(); // Increment session progress (each reaction gives 2 stamina) farmingState.sessionProgress += 2; saveSessionState(); updateHUDDisplay(); return true; } return false; } function goNextPage() { let nextBtn = document.querySelector("body > div.chapter-info > div > a.nextchap"); if (nextBtn) { window.location.href = nextBtn.href; return true; } else { updateStatus('❌ Next button not found'); return false; } } function farmLoop() { if (!farmingState.isRunning || farmingState.isPaused) { return; } updateHUDDisplay(); const stopCheck = checkStopConditions(); if (stopCheck.shouldStop) { updateStatus(`Stopped: ${stopCheck.reason}`); stopFarming(); return; } updateStatus('Clicking reaction...'); if (clickReaction()) { updateStatus('Reaction clicked, going to next page...'); setTimeout(() => { if (goNextPage()) { // Page navigation will restart the script } else { // If can't navigate, stop farming stopFarming(); } }, 1500); } else { updateStatus('❌ Reaction not found'); // Retry in 5 seconds setTimeout(() => farmLoop(), 5000); } } // --- Auto-login Functions --- function autoLogin() { if (!window.location.href.includes("signin.php")) return false; const emailInput = document.evaluate('//*[@id="login-container"]/form/input[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; const passwordInput = document.evaluate('//*[@id="login-container"]/form/input[2]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; const loginBtn = document.evaluate('//*[@id="login-container"]/form/input[3]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (emailInput && passwordInput && loginBtn && AUTO_LOGIN_EMAIL !== "YOUR_EMAIL_HERE") { emailInput.value = AUTO_LOGIN_EMAIL; passwordInput.value = AUTO_LOGIN_PASSWORD; loginBtn.click(); return true; } return false; } function handleLoggedOut() { if (window.location.href.includes("/chapter/")) { const loginBtn = document.evaluate( '//*[@id="discuscontainer"]/div[1]/div[3]/div[5]/a[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if (loginBtn) { // Save current page to resume after login localStorage.setItem("veyra_resume_page", window.location.href); // Navigate to login page window.location.href = "https://demonicscans.org/signin.php"; return true; } } return false; } function handleLoginRedirect() { // If on login page, try auto-login if (window.location.href.includes("signin.php")) { autoLogin(); return true; } // If came back from login, resume to saved page const resumePage = localStorage.getItem("veyra_resume_page"); if (resumePage && resumePage !== window.location.href) { localStorage.removeItem("veyra_resume_page"); window.location.href = resumePage; return true; } return false; } // --- Main Initialization --- function initialize() { // Load saved state first loadSessionState(); // Handle login/logout scenarios if (handleLoggedOut() || handleLoginRedirect()) { return; // Page will redirect } // Only create HUD on chapter pages if (!window.location.href.match(/https:\/\/demonicscans\.org\/title\/.*\/chapter\/.*/)) { return; // Not a chapter page, don't load HUD } // Create and show HUD createHUD(); // Wait for page elements to load, then update display function waitForElements() { const 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) { updateHUDDisplay(); // If user had started farming in previous session, auto-resume if (farmingState.hasStartedThisSession) { farmingState.isRunning = true; farmingState.isPaused = false; updateStatus('Session restored. Auto-resuming farming...'); setTimeout(() => farmLoop(), 2000); } else { updateStatus('Ready to farm'); } } else { setTimeout(waitForElements, 500); } } waitForElements(); } // Start the script initialize(); })();