Autofarm V7

FarmGod auto-farm with configurable Enter interval and FarmGod call interval

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

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

})();