Auto Scavenging - Tutte le Unità

Automates scavenging in Tribal Wars.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Auto Scavenging - Tutte le Unità
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  Automates scavenging in Tribal Wars.
// @author       MrNobody97
// @match        https://*.tribals.it/game.php?*screen=place&mode=scavenge*
// @credit       ricardofauch
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // Definizione delle unità
    const UNITS = [
        { name: 'spear', label: 'Lanciere', include: true },
        { name: 'sword', label: 'Spadaccino', include: false },
        { name: 'axe', label: 'Guerrieri con Ascia', include: false },
        { name: 'light', label: 'Cavalleria Leggera', include: false },
        { name: 'heavy', label: 'Cavalleria Pesante', include: false },
        { name: 'knight', label: 'Paladino', include: false },
    ];

    // Configurazione
    const CONFIG = {
        TOTAL_SPEARS: 100,           // Lancieri totali
        MAX_SPEAR_PERCENTAGE: 1.00,  // Percentuale massima di lancieri per run
        MIN_SPEARS_THRESHOLD: 20,    // Minimo lancieri necessari
        UI_LOAD_DELAY: 6000,         // Ritardo per il caricamento dell'UI
        INPUT_PROCESS_DELAY: 1000,   // Ritardo dopo l'impostazione degli input
        INPUT_RETRY_DELAY: 200,      // Ritardo tra i tentativi di input
        MAX_INPUT_RETRIES: 5,        // Massimo numero di tentativi di input
        MIN_RELOAD_TIME: 8,          // Tempo minimo di ricarica (minuti)
        MAX_RELOAD_TIME: 12,         // Tempo massimo di ricarica (minuti)
        DEBUG: true                  // Abilita/disabilita il debug
    };

    // Inietta gli stili CSS
    function injectStyles() {
        const styles = `
            #scavengeUI {
                position: fixed;
                left: 8%;
                top: 50%;
                transform: translateY(-50%);
                background-color: rgba(245, 245, 245, 0.95);
                border: 1px solid #967444;
                border-radius: 4px;
                padding: 8px;
                z-index: 9999;
                width: 160px;
                height: auto;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            }
            #scavengeUI .title {
                font-weight: bold;
                color: #784B25;
                font-size: 12px;
                margin-bottom: 10px;
                text-align: center;
                font-family: Arial, sans-serif;
            }
            #scavengeUI label {
                display: block;
                color: #5C3C1D;
                font-size: 11px;
                font-weight: bold;
                margin-bottom: 4px;
                font-family: Arial, sans-serif;
                text-align: center;
            }
            #scavengeUI input[type="number"] {
                width: 100%;
                padding: 4px;
                border: 1px solid #967444;
                background-color: white;
                color: #4A3011;
                border-radius: 2px;
                font-size: 12px;
                font-weight: bold;
                text-align: center;
                outline: none;
                box-sizing: border-box;
                margin-bottom: 10px;
            }
            #scavengeUI .checkbox-container {
                display: flex;
                align-items: center;
                justify-content: center;
                margin: 4px 0;
                padding: 4px;
                background-color: rgba(255, 255, 255, 0.5);
                border-radius: 2px;
            }
            #scavengeUI .checkbox-container input[type="checkbox"] {
                margin-right: 5px;
            }
            #scavengeUI input:focus {
                border-color: #784B25;
                box-shadow: 0 0 2px #967444;
            }
            #scavengeUI:hover {
                background-color: rgba(255, 255, 255, 0.98);
            }
            #debugOutput {
                margin-top: 10px;
                padding-top: 10px;
                font-family: Arial, sans-serif;
                font-size: 10px;
                color: #5C3C1D;
            }
            #nextReloadTime {
                margin-top: 8px;
                padding: 4px;
                background-color: rgba(255, 255, 255, 0.5);
                border-radius: 2px;
                text-align: center;
                font-size: 11px;
                font-weight: bold;
                color: #5C3C1D;
            }
            #startTimer {
                margin-top: 8px;
                padding: 4px;
                background-color: rgba(255, 255, 255, 0.5);
                border-radius: 2px;
                text-align: center;
                font-size: 11px;
                font-weight: bold;
                color: #5C3C1D;
            }
            .debug-entry {
                margin-bottom: 4px;
                padding: 2px;
                border-radius: 2px;
            }
            .debug-entry.info { color: #0066cc; }
            .debug-entry.warning { color: #cc6600; }
            .debug-entry.error { color: #cc0000; }
            .debug-entry.success { color: #006600; }
        `;
        const styleElement = document.createElement('style');
        styleElement.textContent = styles;
        document.head.appendChild(styleElement);
    }

    // Crea l'interfaccia utente
    function createUI() {
        const ui = document.createElement('div');
        ui.id = 'scavengeUI';
        ui.innerHTML = `
            <div class="title">Auto Scav</div>
            <label for="totalSpears">Lancieri Tot</label>
            <input type="number" id="totalSpears" min="0" step="1">
            <div id="unitCheckboxes"></div>
            <div id="nextReloadTime">Refresh Pagina in: --:--</div>
            <div id="startTimer">Avvio tra: --:--</div>
            <div id="debugOutput"></div>
        `;
        document.body.appendChild(ui);

        // Aggiungi i checkbox per ogni unità
        const unitCheckboxes = document.getElementById('unitCheckboxes');
        UNITS.forEach(unit => {
            const checkboxContainer = document.createElement('div');
            checkboxContainer.className = 'checkbox-container';
            checkboxContainer.innerHTML = `
                <input type="checkbox" id="include${unit.name}" ${unit.include ? 'checked' : ''}>
                <label for="include${unit.name}">Includi ${unit.label}?</label>
            `;
            unitCheckboxes.appendChild(checkboxContainer);

            // Aggiungi event listener per salvare le preferenze
            const checkbox = checkboxContainer.querySelector(`#include${unit.name}`);
            checkbox.addEventListener('change', (e) => {
                unit.include = e.target.checked;
                localStorage.setItem(`scavengeInclude${unit.name}`, unit.include);
                debugLog(`Includi ${unit.label} aggiornato a: ${unit.include}`, 'info');
            });
        });

        // Carica i valori salvati
        const totalSpearsInput = document.getElementById('totalSpears');
        const savedSpears = localStorage.getItem('scavengeTotalSpears');
        if (savedSpears) {
            CONFIG.TOTAL_SPEARS = parseInt(savedSpears);
            totalSpearsInput.value = CONFIG.TOTAL_SPEARS;
        } else {
            totalSpearsInput.value = CONFIG.TOTAL_SPEARS;
        }

        // Carica le preferenze delle unità
        UNITS.forEach(unit => {
            const savedSetting = localStorage.getItem(`scavengeInclude${unit.name}`);
            if (savedSetting !== null) {
                unit.include = savedSetting === 'true';
                const checkbox = document.getElementById(`include${unit.name}`);
                if (checkbox) checkbox.checked = unit.include;
            }
        });
    }

    // Log di debug
    function debugLog(message, type = 'info') {
        if (!CONFIG.DEBUG) return;

        const styles = {
            info: 'color: #0099ff; font-weight: bold;',
            warning: 'color: #ffa500; font-weight: bold;',
            error: 'color: #ff0000; font-weight: bold;',
            success: 'color: #00ff00; font-weight: bold;'
        };

        const timestamp = new Date().toLocaleTimeString();
        console.log(`%c[${timestamp}] ${message}`, styles[type]);

        // Aggiorna l'output di debug nell'UI
        const debugOutput = document.getElementById('debugOutput');
        if (debugOutput) {
            const entry = document.createElement('div');
            entry.className = `debug-entry ${type}`;
            entry.textContent = `[${timestamp}] ${message}`;
            debugOutput.insertBefore(entry, debugOutput.firstChild);

            // Mantieni solo gli ultimi 4 messaggi
            while (debugOutput.children.length > 4) {
                debugOutput.removeChild(debugOutput.lastChild);
            }
        }
    }

    // Funzione per aggiornare il timer di avvio
    function updateStartTimer(seconds) {
        const startTimerElement = document.getElementById('startTimer');
        if (!startTimerElement) return;

        const minutes = Math.floor(seconds / 60);
        const secs = seconds % 60;
        startTimerElement.textContent = `Avvio tra: ${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;

        if (seconds > 0) {
            setTimeout(() => updateStartTimer(seconds - 1), 1000);
        } else {
            startTimerElement.textContent = 'Avvio in corso...';
        }
    }

    // Funzione principale per lo scavenging
    async function handleScavenging() {
        debugLog('=== Starting scavenging operation ===', 'info');

        // Imposta il timer di avvio (es. 10 secondi)
        const startDelay = 10; // Tempo in secondi
        updateStartTimer(startDelay);

        // Attendi il tempo di avvio
        await new Promise(resolve => setTimeout(resolve, startDelay * 1000));

        // Attendi il caricamento dell'UI
        await new Promise(resolve => setTimeout(resolve, CONFIG.UI_LOAD_DELAY));

        // Trova i pulsanti di avvio
        const startButtons = Array.from(document.querySelectorAll('a.btn.free_send_button'));
        if (startButtons.length === 0) {
            debugLog('Nessun pulsante di avvio trovato!', 'error');
            scheduleReload();
            return;
        }

        // Trova il numero di unità disponibili
        const availableUnits = {};
        UNITS.forEach(unit => {
            const unitLink = document.querySelector(`a.units-entry-all[data-unit="${unit.name}"]`);
            if (unitLink) {
                availableUnits[unit.name] = extractNumber(unitLink.textContent);
                debugLog(`${unit.label} disponibili: ${availableUnits[unit.name]}`, 'info');
            } else {
                availableUnits[unit.name] = 0;
                debugLog(`${unit.label} non trovati!`, 'warning');
            }
        });

        // Verifica se ci sono abbastanza unità
        let hasEnoughUnits = false;
        UNITS.forEach(unit => {
            if (unit.include && availableUnits[unit.name] > 0) {
                hasEnoughUnits = true;
            }
        });

        if (!hasEnoughUnits) {
            debugLog('Unità insufficienti, in attesa del prossimo ricaricamento', 'warning');
            scheduleReload();
            return;
        }

        // Calcola le unità da inviare
        const unitsToSend = {};
        UNITS.forEach(unit => {
            if (unit.include) {
                unitsToSend[unit.name] = Math.min(
                    availableUnits[unit.name],
                    Math.floor(CONFIG.TOTAL_SPEARS / startButtons.length)
                );
                debugLog(`${unit.label} da inviare: ${unitsToSend[unit.name]}`, 'info');
            }
        });

        // Trova e imposta gli input
        let allInputsSuccess = true;
        UNITS.forEach(unit => {
            if (unit.include) {
                const input = document.querySelector(`input[name="${unit.name}"].unitsInput.input-nicer`);
                if (input) {
                    const success = setInputValueWithVerification(input, unitsToSend[unit.name]);
                    if (!success) allInputsSuccess = false;
                } else {
                    debugLog(`Input per ${unit.label} non trovato!`, 'error');
                    allInputsSuccess = false;
                }
            }
        });

        if (!allInputsSuccess) {
            debugLog('Impossibile impostare i valori degli input, ricaricamento in corso...', 'error');
            scheduleReload();
            return;
        }

        // Clicca il pulsante di avvio
        const lastButton = startButtons[startButtons.length - 1];
        debugLog('Cliccando il pulsante di avvio...', 'info');
        lastButton.click();

        // Ricarica la pagina
        setTimeout(() => {
            window.location.reload();
        }, 1000);
    }

    // Funzione per estrarre numeri dal testo
    function extractNumber(text) {
        const match = text.match(/\((\d+)\)/);
        return match ? parseInt(match[1]) : 0;
    }

    // Funzione per impostare i valori degli input con verifica
    async function setInputValueWithVerification(input, value, retryCount = 0) {
        debugLog(`Tentativo ${retryCount + 1} per impostare ${input.name} a ${value}`, 'info');

        input.value = value;
        input.dispatchEvent(new Event('input', { bubbles: true }));
        input.dispatchEvent(new Event('change', { bubbles: true }));

        await new Promise(resolve => setTimeout(resolve, CONFIG.INPUT_RETRY_DELAY));

        if (input.value !== value.toString()) {
            debugLog(`Verifica fallita per ${input.name}! Valore attuale: ${input.value}`, 'warning');

            if (retryCount < CONFIG.MAX_INPUT_RETRIES) {
                debugLog(`Riprova... (${retryCount + 1}/${CONFIG.MAX_INPUT_RETRIES})`, 'info');
                return setInputValueWithVerification(input, value, retryCount + 1);
            } else {
                debugLog('Massimo numero di tentativi raggiunto!', 'error');
                return false;
            }
        }

        debugLog(`${input.name} impostato correttamente`, 'success');
        return true;
    }

    // Funzione per programmare il ricaricamento della pagina
    function scheduleReload() {
        const reloadTime = (Math.random() * (CONFIG.MAX_RELOAD_TIME - CONFIG.MIN_RELOAD_TIME) + CONFIG.MIN_RELOAD_TIME) * 60 * 1000;
        const nextReloadTime = new Date(Date.now() + reloadTime);
        const timeString = nextReloadTime.toLocaleTimeString('it-IT', { hour: '2-digit', minute: '2-digit' });

        const nextReloadElement = document.getElementById('nextReloadTime');
        if (nextReloadElement) {
            nextReloadElement.textContent = `Ricarico alle: ${timeString}`;
        }

        debugLog(`Prossimo ricaricamento alle: ${timeString}`, 'info');
        setTimeout(() => {
            debugLog('Esecuzione del ricaricamento...', 'info');
            window.location.reload();
        }, reloadTime);
    }

    // Avvia lo script
    debugLog('=== Script inizializzato ===', 'info');
    injectStyles();
    createUI();
    handleScavenging();
})();