Auto Scavenging - Tutte le Unità

Automates scavenging in Tribal Wars.

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