// ==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();
})();