FarmGod auto-farm with configurable Enter interval and FarmGod call interval
// ==UserScript==
// @name Autofarm V7
// @version 7
// @include https://*/game.php*screen=am_farm*
// @namespace https://greasyfork.org/users/1388863
// @description FarmGod auto-farm with configurable Enter interval and FarmGod call interval
// @grant none
// ==/UserScript==
(function () {
'use strict';
const domain = window.location.hostname.split('.')[0];
// --- Default settings ---
const DEFAULTS = {
isRunning: false,
enterMin: 250,
enterMax: 500,
reloadMin: 600,
reloadMax: 900,
webhookUrl: ''
};
function loadSettings() {
try {
const saved = JSON.parse(localStorage.getItem(domain + '_autofarm_settings') || '{}');
return Object.assign({}, DEFAULTS, saved);
} catch (e) {
return Object.assign({}, DEFAULTS);
}
}
function saveSettings(s) {
localStorage.setItem(domain + '_autofarm_settings', JSON.stringify(s));
}
function loadPosition() {
try {
return JSON.parse(localStorage.getItem(domain + '_autofarm_pos') || 'null');
} catch (e) { return null; }
}
function savePosition(x, y) {
localStorage.setItem(domain + '_autofarm_pos', JSON.stringify({ x, y }));
}
let settings = loadSettings();
let isRunning = JSON.parse(localStorage.getItem(domain + '_isRunning')) || false;
let intervalId;
let countdownInterval;
let emptyFarmChecks = 0;
let captchaAlertSent = false;
const EMPTY_FARM_THRESHOLD = 4;
function randomDelay(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// --- FarmGod completion detection ---
function hasFarmsRemaining() {
// Strategy 1: FarmGod progress bar text (e.g. "8 / 8")
const allElements = document.querySelectorAll('*');
for (const el of allElements) {
if (el.children.length > 0) continue;
const text = (el.innerText || el.textContent || '').trim();
const match = text.match(/^(\d+)\s*\/\s*(\d+)$/);
if (match) {
const current = parseInt(match[1]);
const total = parseInt(match[2]);
if (total > 0) {
console.log(`[Autofarm] FarmGod Fortschritt: ${current}/${total}`);
return current < total;
}
}
}
// Strategy 2: progress bar at 100% width
const progressBars = document.querySelectorAll(
'.progress-bar, .farmgod_bar, [class*="progress"], [id*="progress"], [style*="width: 100%"]'
);
for (const bar of progressBars) {
const style = bar.getAttribute('style') || '';
const computedWidth = window.getComputedStyle(bar).width;
const parentWidth = bar.parentElement
? window.getComputedStyle(bar.parentElement).width
: null;
if (style.includes('width: 100%') || style.includes('width:100%')) {
console.log('[Autofarm] Fortschrittsbalken bei 100% erkannt.');
return false;
}
if (parentWidth && computedWidth === parentWidth) {
console.log('[Autofarm] Fortschrittsbalken füllt Parent komplett.');
return false;
}
}
// Strategy 3: FarmGod table rows (exclude "Letzte Plünderungen")
const allTables = document.querySelectorAll('table');
for (const table of allTables) {
const section = table.closest
? table.closest('[id*="last"], [class*="last"], [id*="report"], [class*="report"]')
: null;
if (section) continue;
const heading = table.previousElementSibling;
if (heading && /letzte|plünderung|report/i.test(heading.textContent)) continue;
const rows = table.querySelectorAll('tbody tr');
if (rows.length > 0) return true;
}
return false;
}
// --- Captcha detection ---
function isCaptchaPresent() {
const selectors = [
'#captcha', '.captcha',
'iframe[src*="captcha"]', 'iframe[src*="recaptcha"]',
'.g-recaptcha', '#recaptcha',
'form[action*="captcha"]',
'[class*="captcha"]', '[id*="captcha"]'
];
for (const sel of selectors) {
if (document.querySelector(sel)) return true;
}
return false;
}
function sendDiscordAlert() {
settings = loadSettings();
const webhookUrl = settings.webhookUrl;
if (!webhookUrl || webhookUrl.trim() === '') {
console.warn('[Autofarm] Kein Discord Webhook hinterlegt – Alert übersprungen.');
return;
}
const payload = {
username: 'Autofarm V7',
avatar_url: 'https://i.imgur.com/4M34hi2.png',
embeds: [{
title: '⚠️ Captcha erkannt!',
description: 'Der Autofarm wurde gestoppt weil ein Captcha erkannt wurde.',
color: 0xe74c3c,
fields: [
{ name: '🌐 Server', value: domain, inline: true },
{ name: '🕒 Zeit', value: new Date().toLocaleString('de-DE'), inline: true },
{ name: '🔗 Seite', value: window.location.href, inline: false }
],
footer: { text: 'Autofarm V7 – Captcha Alert' }
}]
};
fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.ok
? console.log('[Autofarm] Discord Alert gesendet.')
: console.error('[Autofarm] Discord Alert fehlgeschlagen:', res.status))
.catch(err => console.error('[Autofarm] Discord Webhook Fehler:', err));
}
function handleCaptchaDetected() {
if (captchaAlertSent) return;
captchaAlertSent = true;
console.warn('[Autofarm] ⚠️ Captcha erkannt! Stoppe Autofarm...');
sendDiscordAlert();
stopProcess();
const countdownElement = document.getElementById('af-countdown');
if (countdownElement) {
countdownElement.style.display = 'block';
countdownElement.style.color = '#e74c3c';
countdownElement.innerText = '⚠️ Captcha erkannt! Autofarm gestoppt.';
}
}
function startCaptchaObserver() {
const observer = new MutationObserver(() => {
if (isRunning && isCaptchaPresent()) handleCaptchaDetected();
});
observer.observe(document.body, { childList: true, subtree: true });
if (isCaptchaPresent()) handleCaptchaDetected();
}
function pressEnterRandomly() {
settings = loadSettings();
const delay = randomDelay(settings.enterMin, settings.enterMax);
document.dispatchEvent(new KeyboardEvent('keydown', {
key: 'Enter', code: 'Enter', which: 13, keyCode: 13, bubbles: true
}));
setTimeout(() => {
if (!hasFarmsRemaining()) {
emptyFarmChecks++;
console.log(`[Autofarm] Keine Farmen erkannt (${emptyFarmChecks}/${EMPTY_FARM_THRESHOLD})`);
if (emptyFarmChecks >= EMPTY_FARM_THRESHOLD) {
console.log('[Autofarm] Farmliste leer – Enter-Loop pausiert.');
clearTimeout(intervalId);
const cd = document.getElementById('af-countdown');
if (cd) cd.style.color = '#e74c3c';
startCountdown();
return;
}
} else {
emptyFarmChecks = 0;
const cd = document.getElementById('af-countdown');
if (cd) cd.style.color = '#f0a500';
}
}, 300);
intervalId = setTimeout(pressEnterRandomly, delay);
}
function loadFarmGodScript() {
$.getScript('https://higamy.github.io/TW/Scripts/Approved/FarmGodCopy.js')
.done((s, t) => console.log('[Autofarm] FarmGod loaded:', t))
.fail((j, s, e) => console.error('[Autofarm] Error loading FarmGod:', e));
}
function clickOptionButton(retries = 3) {
const button = document.querySelector('input.btn.optionButton[value="Plan farms"]');
if (button) {
button.click();
console.log('[Autofarm] "Plan farms" clicked');
} else if (retries > 0) {
setTimeout(() => clickOptionButton(retries - 1), randomDelay(2000, 4000));
}
}
function startProcess() {
console.log('[Autofarm] Starting...');
captchaAlertSent = false;
setTimeout(() => {
loadFarmGodScript();
setTimeout(() => {
clickOptionButton();
setTimeout(() => pressEnterRandomly(), randomDelay(3000, 5000));
}, randomDelay(3000, 5000));
}, randomDelay(4000, 7000));
}
function stopProcess() {
clearTimeout(intervalId);
clearInterval(countdownInterval);
isRunning = false;
localStorage.setItem(domain + '_isRunning', false);
updateButtonState();
const cd = document.getElementById('af-countdown');
if (cd && !captchaAlertSent) cd.style.display = 'none';
console.log('[Autofarm] Stopped.');
}
function toggleProcess() {
if (isRunning) {
stopProcess();
} else {
startProcess();
isRunning = true;
localStorage.setItem(domain + '_isRunning', true);
updateButtonState();
}
}
function startCountdown() {
settings = loadSettings();
const cd = document.getElementById('af-countdown');
let timeLeft = randomDelay(settings.reloadMin, settings.reloadMax);
if (cd) cd.style.display = 'block';
countdownInterval = setInterval(() => {
if (timeLeft <= 0) {
clearInterval(countdownInterval);
if (cd) cd.style.display = 'none';
location.reload();
} else {
if (cd) cd.innerText = `Nächster Loop in: ${Math.floor(timeLeft / 60)}m ${timeLeft % 60}s`;
timeLeft--;
}
}, 1000);
}
function updateButtonState() {
const btn = document.getElementById('af-toggle-btn');
if (!btn) return;
btn.textContent = isRunning ? 'Stop Looting' : 'Start Looting';
btn.style.backgroundColor = isRunning ? '#c0392b' : '#27ae60';
}
// --- Drag & Drop ---
function makeDraggable(container, handle) {
let isDragging = false;
let startX, startY, startLeft, startTop;
handle.style.cursor = 'grab';
handle.addEventListener('mousedown', (e) => {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
startLeft = parseInt(container.style.left) || 0;
startTop = parseInt(container.style.top) || 0;
handle.style.cursor = 'grabbing';
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const dx = e.clientX - startX;
const dy = e.clientY - startY;
const newLeft = Math.max(0, Math.min(window.innerWidth - container.offsetWidth, startLeft + dx));
const newTop = Math.max(0, Math.min(window.innerHeight - container.offsetHeight, startTop + dy));
container.style.left = newLeft + 'px';
container.style.top = newTop + 'px';
container.style.bottom = 'auto';
container.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
if (!isDragging) return;
isDragging = false;
handle.style.cursor = 'grab';
savePosition(parseInt(container.style.left), parseInt(container.style.top));
});
// Touch support
handle.addEventListener('touchstart', (e) => {
const touch = e.touches[0];
isDragging = true;
startX = touch.clientX;
startY = touch.clientY;
startLeft = parseInt(container.style.left) || 0;
startTop = parseInt(container.style.top) || 0;
e.preventDefault();
}, { passive: false });
document.addEventListener('touchmove', (e) => {
if (!isDragging) return;
const touch = e.touches[0];
const dx = touch.clientX - startX;
const dy = touch.clientY - startY;
const newLeft = Math.max(0, Math.min(window.innerWidth - container.offsetWidth, startLeft + dx));
const newTop = Math.max(0, Math.min(window.innerHeight - container.offsetHeight, startTop + dy));
container.style.left = newLeft + 'px';
container.style.top = newTop + 'px';
container.style.bottom = 'auto';
container.style.right = 'auto';
e.preventDefault();
}, { passive: false });
document.addEventListener('touchend', () => {
if (!isDragging) return;
isDragging = false;
savePosition(parseInt(container.style.left), parseInt(container.style.top));
});
}
function initializeUI() {
const existing = document.getElementById('af-container');
if (existing) existing.remove();
const container = document.createElement('div');
container.id = 'af-container';
// Restore saved position or default to bottom-left
const savedPos = loadPosition();
Object.assign(container.style, {
position: 'fixed',
backgroundColor: '#2c2c2c',
color: '#fff',
padding: '12px 14px',
borderRadius: '8px',
zIndex: 10000,
fontFamily: 'Arial, sans-serif',
fontSize: '13px',
minWidth: '240px',
boxShadow: '0 4px 12px rgba(0,0,0,0.5)'
});
if (savedPos) {
container.style.left = savedPos.x + 'px';
container.style.top = savedPos.y + 'px';
} else {
container.style.bottom = '20px';
container.style.left = '20px';
}
// Title (drag handle)
const title = document.createElement('div');
title.textContent = '⚔ Autofarm V7';
Object.assign(title.style, {
fontWeight: 'bold',
fontSize: '14px',
marginBottom: '10px',
borderBottom: '1px solid #555',
paddingBottom: '6px',
userSelect: 'none'
});
container.appendChild(title);
const countdown = document.createElement('div');
countdown.id = 'af-countdown';
countdown.style.display = 'none';
Object.assign(countdown.style, {
marginBottom: '8px',
color: '#f0a500',
fontWeight: 'bold'
});
container.appendChild(countdown);
function addSetting(label, idMin, idMax, defaultMin, defaultMax, unit) {
const row = document.createElement('div');
Object.assign(row.style, { marginBottom: '7px' });
const lbl = document.createElement('div');
lbl.textContent = label;
lbl.style.marginBottom = '2px';
lbl.style.color = '#aaa';
row.appendChild(lbl);
const inputs = document.createElement('div');
Object.assign(inputs.style, { display: 'flex', gap: '6px', alignItems: 'center' });
function makeInput(id, value) {
const inp = document.createElement('input');
inp.id = id; inp.type = 'number'; inp.value = value; inp.min = 0;
Object.assign(inp.style, {
width: '70px', padding: '3px 5px', borderRadius: '4px',
border: '1px solid #555', backgroundColor: '#1a1a1a',
color: '#fff', fontSize: '12px'
});
return inp;
}
inputs.appendChild(makeInput(idMin, defaultMin));
const dash = document.createElement('span');
dash.textContent = '–'; dash.style.color = '#aaa';
inputs.appendChild(dash);
inputs.appendChild(makeInput(idMax, defaultMax));
const unitSpan = document.createElement('span');
unitSpan.textContent = unit; unitSpan.style.color = '#aaa';
inputs.appendChild(unitSpan);
row.appendChild(inputs);
return row;
}
container.appendChild(addSetting('Enter-Intervall (Enter-Tempo):', 'af-enter-min', 'af-enter-max', settings.enterMin, settings.enterMax, 'ms'));
container.appendChild(addSetting('Reload-Intervall (Loop-Zeit):', 'af-reload-min', 'af-reload-max', settings.reloadMin, settings.reloadMax, 's'));
const webhookRow = document.createElement('div');
Object.assign(webhookRow.style, { marginBottom: '7px' });
const webhookLabel = document.createElement('div');
webhookLabel.textContent = '🔔 Discord Webhook URL:';
webhookLabel.style.marginBottom = '2px';
webhookLabel.style.color = '#aaa';
webhookRow.appendChild(webhookLabel);
const webhookInput = document.createElement('input');
webhookInput.id = 'af-webhook-url';
webhookInput.type = 'text';
webhookInput.placeholder = 'https://discord.com/api/webhooks/...';
webhookInput.value = settings.webhookUrl || '';
Object.assign(webhookInput.style, {
width: '100%', padding: '3px 5px', borderRadius: '4px',
border: '1px solid #555', backgroundColor: '#1a1a1a',
color: '#fff', fontSize: '11px', boxSizing: 'border-box'
});
webhookRow.appendChild(webhookInput);
container.appendChild(webhookRow);
const saveBtn = document.createElement('button');
saveBtn.textContent = 'Einstellungen speichern';
Object.assign(saveBtn.style, {
display: 'block', width: '100%', padding: '5px', marginBottom: '8px',
border: 'none', borderRadius: '4px', cursor: 'pointer',
backgroundColor: '#2980b9', color: '#fff', fontSize: '12px'
});
saveBtn.addEventListener('click', () => {
const newSettings = {
enterMin: Math.max(50, parseInt(document.getElementById('af-enter-min').value) || DEFAULTS.enterMin),
enterMax: Math.max(50, parseInt(document.getElementById('af-enter-max').value) || DEFAULTS.enterMax),
reloadMin: Math.max(10, parseInt(document.getElementById('af-reload-min').value) || DEFAULTS.reloadMin),
reloadMax: Math.max(10, parseInt(document.getElementById('af-reload-max').value) || DEFAULTS.reloadMax),
webhookUrl: document.getElementById('af-webhook-url').value.trim()
};
if (newSettings.enterMin > newSettings.enterMax)
[newSettings.enterMin, newSettings.enterMax] = [newSettings.enterMax, newSettings.enterMin];
if (newSettings.reloadMin > newSettings.reloadMax)
[newSettings.reloadMin, newSettings.reloadMax] = [newSettings.reloadMax, newSettings.reloadMin];
saveSettings(newSettings);
settings = newSettings;
saveBtn.textContent = '✓ Gespeichert!';
setTimeout(() => { saveBtn.textContent = 'Einstellungen speichern'; }, 1500);
});
container.appendChild(saveBtn);
const controlButton = document.createElement('button');
controlButton.id = 'af-toggle-btn';
Object.assign(controlButton.style, {
display: 'block', width: '100%', padding: '7px',
border: 'none', borderRadius: '4px', cursor: 'pointer',
color: '#fff', fontSize: '13px', fontWeight: 'bold'
});
controlButton.addEventListener('click', toggleProcess);
container.appendChild(controlButton);
document.body.appendChild(container);
updateButtonState();
// Make draggable via title bar
makeDraggable(container, title);
}
initializeUI();
startCaptchaObserver();
if (isRunning) {
console.log('[Autofarm] Resuming from saved state...');
startProcess();
} else {
console.log('[Autofarm] Ready. Press Start Looting to begin.');
}
})();