// ==UserScript== // @name TW Auto-Action (Hotkey & Externe Trigger) // @namespace TribalWars // @version 3.35 // Version auf 3.35 aktualisiert - Statusleiste nun direkt neben den Buttons // @description Klickt den ersten FarmGod Button (A oder B) in zufälligem Intervall. Start/Stop per Tastenkombination (Standard: Shift+Strg+E) oder durch Aufruf von window.toggleTribalAutoAction(). Einstellungs-Button auf der Farm-Seite. // @author Idee PhilJor93 Generiert mit Google Gemini-KI // @match https://*.die-staemme.de/game.php?* // @grant none // ==/UserScript== (function() { 'use strict'; // *** AGGRESSIVER SCHUTZ VOR MEHRFACHAUSFÜHRUNG *** if (window.TW_AUTO_ENTER_INITIALIZED_MARKER === true) { return; } window.TW_AUTO_ENTER_INITIALIZED_MARKER = true; const SCRIPT_VERSION = '3.35'; // Die aktuelle Version des Skripts // Speichert den ursprünglichen Titel des Dokuments const originalDocumentTitle = document.title; // --- Sound-Profile Definitionen --- // Hier können weitere Sounds hinzugefügt oder bestehende angepasst werden const soundProfiles = { 'default': { name: 'Standard (Hell)', frequency: 660, type: 'sine', duration: 0.8, volume: 0.5 }, 'alarm': { name: 'Alarm (Kurz & Hoch)', frequency: 880, type: 'triangle', duration: 0.4, volume: 0.6 }, 'chime': { name: 'Glocke (Tief & Langsam)', frequency: 440, type: 'sine', duration: 1.2, volume: 0.4 }, 'beep': { name: 'Beep (Standard-Signal)', frequency: 750, type: 'square', duration: 0.2, volume: 0.7 }, 'high_alert': { name: 'Hoher Alarm', frequency: 1000, type: 'sawtooth', duration: 0.3, volume: 0.7 }, 'soft_chime': { name: 'Sanfte Glocke', frequency: 523.25, type: 'sine', duration: 0.6, volume: 0.4 }, // C5 'deep_thump': { name: 'Tiefer Puls', frequency: 120, type: 'square', duration: 0.5, volume: 0.8 }, 'quick_blip': { name: 'Kurzer Blip', frequency: 1500, type: 'sine', duration: 0.1, volume: 0.6 } }; // --- Standardeinstellungen --- const defaultSettings = { minInterval: 200, maxInterval: 500, toggleKeyCode: 'KeyE', // Standard: 'E' toggleKeyChar: 'E', // Zeichen für die Anzeige im UI requiredCtrl: true, requiredAlt: false, requiredShift: true, pauseOnBotProtection: true, // Einstellung: Bei Botschutz pausieren soundEnabled: true, // Botschutz-Ton aktiviert selectedSound: 'default' // Standard: 'default' Sound }; let currentSettings = {}; // Wird aus localStorage geladen // --- Funktionen zum Laden und Speichern der Einstellungen --- function loadSettings() { const savedSettings = localStorage.getItem('tw_auto_action_settings'); if (savedSettings) { try { const parsed = JSON.parse(savedSettings); currentSettings = { ...defaultSettings, ...parsed }; // Sicherstellen, dass toggleKeyChar aus keyCode abgeleitet wird, falls es fehlt if (!currentSettings.toggleKeyChar && currentSettings.toggleKeyCode) { currentSettings.toggleKeyChar = currentSettings.toggleKeyCode.replace('Key', '').replace('Digit', ''); if (currentSettings.toggleKeyCode === 'Space') currentSettings.toggleKeyChar = ' '; } else if (currentSettings.toggleKeyChar && !currentSettings.toggleKeyCode) { // Fallback, falls Char da, aber Code fehlt currentSettings.toggleKeyCode = getKeyCodeFromChar(currentSettings.toggleKeyChar); } // Sicherstellen, dass der ausgewählte Sound existiert, sonst auf 'default' zurückfallen if (!soundProfiles[currentSettings.selectedSound]) { currentSettings.selectedSound = 'default'; } } catch (e) { console.error("Auto-Action: Fehler beim Laden der Einstellungen, verwende Standardeinstellungen:", e); currentSettings = { ...defaultSettings }; } } else { currentSettings = { ...defaultSettings }; } } function saveSettings() { localStorage.setItem('tw_auto_action_settings', JSON.stringify(currentSettings)); } // --- Hilfsfunktion zum Umwandeln von Zeichen in event.code --- function getKeyCodeFromChar(char) { if (!char) return null; char = char.toUpperCase(); if (char.length === 1 && char.match(/[A-Z]/)) { return 'Key' + char; } if (char === ' ') return 'Space'; if (char.length === 1 && char.match(/[0-9]/)) { return 'Digit' + char; } return null; } // --- Skript-Variablen --- let autoActionActive = false; let autoActionIntervalId = null; let botProtectionDetected = false; let noFarmButtonsDetected = false; let initialReadyMessageShown = false; // Flag für die initiale Nachricht // --- Hilfsfunktion zum Generieren eines zufälligen Intervalls --- function getRandomInterval(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // --- AudioContext und Sound-Funktionen --- let audioCtx = null; // Globale Referenz für AudioContext // Funktion zum Erzeugen und Abspielen eines Oszillators mit Profil-Parametern function createAndPlayOscillator(profile) { if (!audioCtx || audioCtx.state === 'closed') { console.warn('TW Auto-Action: AudioContext nicht bereit für die Wiedergabe des Oszillators.'); return; } try { const oscillator = audioCtx.createOscillator(); const gainNode = audioCtx.createGain(); oscillator.connect(gainNode); gainNode.connect(audioCtx.destination); oscillator.type = profile.type; oscillator.frequency.setValueAtTime(profile.frequency, audioCtx.currentTime); gainNode.gain.setValueAtTime(profile.volume, audioCtx.currentTime); oscillator.start(); gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + profile.duration); oscillator.stop(audioCtx.currentTime + profile.duration); console.log(`TW Auto-Action: Oszillator-Ton '${profile.name}' gestartet.`); } catch (e) { console.error("TW Auto-Action: FEHLER beim Erzeugen oder Starten des Oszillators.", e); } } // Funktion zum Triggern des Botschutz-Tons (respektiert Einstellung) function triggerAntiBotSound() { console.log('TW Auto-Action: Trigger Botschutz-Ton (geprüft nach Einstellung)...'); if (!currentSettings.soundEnabled) { console.log('TW Auto-Action: Botschutz-Ton ist in den Einstellungen deaktiviert. Überspringe Wiedergabe.'); return; } try { if (!audioCtx || audioCtx.state === 'closed') { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); console.log('TW Auto-Action: AudioContext initialisiert (durch Botschutz-Trigger). Zustand:', audioCtx.state); } const actuallyPlaySound = () => { const profile = soundProfiles[currentSettings.selectedSound] || soundProfiles['default']; console.log('TW Auto-Action: Botschutz-Ton wird abgespielt.'); createAndPlayOscillator(profile); }; if (audioCtx.state === 'suspended') { console.log('TW Auto-Action: AudioContext ist ausgesetzt (durch Botschutz-Trigger), versuche Fortsetzung...'); audioCtx.resume().then(() => { console.log('TW Auto-Action: AudioContext erfolgreich fortgesetzt (durch Botschutz-Trigger).'); actuallyPlaySound(); }).catch(e => { console.error("TW Auto-Action: FEHLER beim Fortsetzen des AudioContext (durch Botschutz-Trigger).", e); }); } else if (audioCtx.state === 'running') { console.log('TW Auto-Action: AudioContext läuft bereits (durch Botschutz-Trigger).'); actuallyPlaySound(); } else { console.warn('TW Auto-Action: AudioContext ist in unerwartetem Zustand (durch Botschutz-Trigger):', audioCtx.state); } } catch (e) { console.error("TW Auto-Action: KRITISCHER FEHLER beim Initialisieren oder Abspielen des Anti-Bot-Sounds (durch Botschutz-Trigger).", e); } } // Funktion für den Aktivierungs-Test-Ton (spielt den aktuell ausgewählten Ton, entsperrt Context) function playActivationTestTone() { console.log('TW Auto-Action: Test-Ton durch Aktivierungs-Button angefordert...'); try { if (!audioCtx || audioCtx.state === 'closed') { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); console.log('TW Auto-Action: AudioContext initialisiert (durch Aktivierungs-Button). Zustand:', audioCtx.state); } // Verwende das aktuell ausgewählte Sound-Profil für den Testton const profileToPlay = soundProfiles[currentSettings.selectedSound] || soundProfiles['default']; if (audioCtx.state === 'suspended') { console.log('TW Auto-Action: AudioContext ist ausgesetzt (durch Aktivierungs-Button), versuche Fortsetzung...'); audioCtx.resume().then(() => { console.log('TW Auto-Action: AudioContext erfolgreich fortgesetzt (durch Aktivierungs-Button), spiele Test-Ton ab.'); createAndPlayOscillator(profileToPlay); }).catch(e => { console.error("TW Auto-Action: FEHLER beim Fortsetzen des AudioContext (durch Aktivierungs-Button).", e); }); } else if (audioCtx.state === 'running') { console.log('TW Auto-Action: AudioContext läuft bereits (durch Aktivierungs-Button), spiele Test-Ton ab.'); createAndPlayOscillator(profileToPlay); } else { console.warn('TW Auto-Action: AudioContext ist in unerwartetem Zustand (durch Aktivierungs-Button):', audioCtx.state); } } catch (e) { console.error("TW Auto-Action: KRITISCHER FEHLER beim Initialisieren oder Abspielen des Test-Tons (durch Aktivierungs-Button).", e); } } // Funktion zum Abspielen des ausgewählten Sounds aus den Einstellungen (für Vorschau) function playSelectedSoundPreview() { const selectedKey = $('#setting_selected_sound').val(); const profile = soundProfiles[selectedKey] || soundProfiles['default']; // Fallback auf Standard console.log(`TW Auto-Action: Spiele Vorschau-Ton: ${profile.name}`); try { if (!audioCtx || audioCtx.state === 'closed') { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); console.log('TW Auto-Action: AudioContext initialisiert (für Vorschau). Zustand:', audioCtx.state); } if (audioCtx.state === 'suspended') { console.log('TW Auto-Action: AudioContext ist ausgesetzt (für Vorschau), versuche Fortsetzung...'); audioCtx.resume().then(() => { console.log('TW Auto-Action: AudioContext erfolgreich fortgesetzt (für Vorschau).'); createAndPlayOscillator(profile); }).catch(e => { console.error("TW Auto-Action: FEHLER beim Fortsetzen des AudioContext (für Vorschau).", e); }); } else if (audioCtx.state === 'running') { console.log('TW Auto-Action: AudioContext läuft bereits (für Vorschau).'); createAndPlayOscillator(profile); } else { console.warn('TW Auto-Action: AudioContext ist in unerwartetem Zustand (für Vorschau):', audioCtx.state); } } catch (e) { console.error("TW Auto-Action: KRITISCHER FEHLER beim Initialisieren oder Abspielen des Vorschau-Tons.", e); } } // --- Botschutz-Erkennung --- function checkAntiBotProtection() { const botProtectionSelectors = [ 'div#botprotection_quest', 'div[data-id="bot_protection"]', '#popup_box_bot_protection', 'div#tooltip:contains("Bot-Schutz")', '#bot_protect_dialog', '.popup_box_container:contains("Sicherheitsabfrage")', '.popup_box_container:contains("Bot-Schutz")', 'div[data-bot-check="true"]', 'img[src*="captcha"]', 'input[name="captcha_code"]', '.modem-window:contains("Sicherheitsprüfung")', '#recaptcha-challenge', '#bot_captcha_div', 'div.error:contains("Bitte bestätigen Sie, dass Sie kein Bot sind.")', ]; let isBotProtectionVisible = false; for (const selector of botProtectionSelectors) { const element = $(selector); if (element.length > 0 && element.is(':visible') && element.css('display') !== 'none' && element.css('visibility') !== 'hidden' && element.attr('disabled') !== 'disabled') { isBotProtectionVisible = true; break; } } if (isBotProtectionVisible) { if (!botProtectionDetected) { botProtectionDetected = true; triggerAntiBotSound(); // Ruft triggerAntiBotSound() auf, die die soundEnabled-Einstellung prüft if (autoActionActive && currentSettings.pauseOnBotProtection) { clearInterval(autoActionIntervalId); autoActionIntervalId = null; autoActionActive = false; if (typeof UI !== 'undefined' && typeof UI.ErrorMessage === 'function') { UI.ErrorMessage('Botschutz-Abfrage erkannt! Auto-Action wurde gestoppt!', 5000); } console.warn('TW Auto-Action: Botschutz-Abfrage erkannt. Skript gestoppt.'); } else if (typeof UI !== 'undefined' && typeof UI.ErrorMessage === 'function') { UI.ErrorMessage('Botschutz-Abfrage erkannt! Auto-Action ist nicht aktiv oder pausiert nicht automatisch.', 5000); } updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons } return true; } else { if (botProtectionDetected) { botProtectionDetected = false; if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { UI.InfoMessage('Botschutz-Abfrage nicht mehr sichtbar. Auto-Action kann bei Bedarf wieder gestartet werden.', 3000); } updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons } return false; } } // --- Funktion zum Simulieren des Button-Klicks --- function simulateButtonClick() { if (typeof game_data !== 'undefined' && game_data.screen === 'am_farm') { if (checkAntiBotProtection()) { return; } const farmButton = $(FARM_BUTTON_SELECTOR).first(); if (farmButton.length > 0 && farmButton.is(':visible') && !farmButton.is(':disabled')) { if (noFarmButtonsDetected) { noFarmButtonsDetected = false; updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons } farmButton.trigger('click'); } else { if (!noFarmButtonsDetected) { noFarmButtonsDetected = true; if (autoActionActive) { clearInterval(autoActionIntervalId); autoActionIntervalId = null; autoActionActive = false; if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { UI.InfoMessage('Keine Farm-Buttons gefunden oder sichtbar. Auto-Action gestoppt!', 3000); } console.log('TW Auto-Action: Keine Farm-Buttons gefunden oder sichtbar. Skript gestoppt.'); } else { if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { UI.InfoMessage('Keine Farm-Buttons gefunden oder sichtbar.', 3000); } } updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons } } } else { if (autoActionActive) { clearInterval(autoActionIntervalId); autoActionIntervalId = null; autoActionActive = false; if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { UI.InfoMessage('Auto-Action automatisch gestoppt (nicht auf Farm-Seite).', 3000); } noFarmButtonsDetected = false; botProtectionDetected = false; updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons } } } // --- Event Listener für Tastendrücke --- document.addEventListener('keydown', (event) => { const isHotkeyCombination = event.code === currentSettings.toggleKeyCode && event.ctrlKey === currentSettings.requiredCtrl && event.altKey === currentSettings.requiredAlt && event.shiftKey === currentSettings.requiredShift; if (isHotkeyCombination) { event.preventDefault(); window.toggleTribalAutoAction(); } }); // --- Globale Toggle Funktion für Auto-Action --- window.toggleTribalAutoAction = function() { if (autoActionActive) { clearInterval(autoActionIntervalId); autoActionIntervalId = null; autoActionActive = false; if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { UI.InfoMessage('Auto-Action gestoppt.', 2000); } noFarmButtonsDetected = false; botProtectionDetected = false; } else { // Beim Starten des Skripts durch Nutzerinteraktion: Versuche AudioContext zu aktivieren if (!audioCtx) { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } if (audioCtx && audioCtx.state === 'suspended') { audioCtx.resume().then(() => { console.log('TW Auto-Action: AudioContext beim Starten fortgesetzt durch Benutzerinteraktion.'); }).catch(e => { console.warn('TW Auto-Action: Fehler beim Fortsetzen des AudioContext beim Starten durch Benutzerinteraktion.', e); }); } if (checkAntiBotProtection()) { // Wenn Botschutz direkt beim Start erkannt wird, wird der Status bereits in checkAntiBotProtection() aktualisiert return; } const farmButtonCheck = $(FARM_BUTTON_SELECTOR).first(); if (farmButtonCheck.length === 0 || !farmButtonCheck.is(':visible') || farmButtonCheck.is(':disabled')) { if (typeof UI !== 'undefined' && typeof UI.ErrorMessage === 'function') { UI.ErrorMessage('Kann Auto-Action nicht starten: Keine Farm-Buttons gefunden oder sie sind nicht sichtbar/aktiv.', 4000); } noFarmButtonsDetected = true; updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons return; } autoActionActive = true; if (autoActionIntervalId) clearInterval(autoActionIntervalId); const initialInterval = getRandomInterval(currentSettings.minInterval, currentSettings.maxInterval); autoActionIntervalId = setInterval(() => { simulateButtonClick(); clearInterval(autoActionIntervalId); if (autoActionActive) { autoActionIntervalId = setInterval(simulateButtonClick, getRandomInterval(currentSettings.minInterval, currentSettings.maxInterval)); } }, initialInterval); if (typeof UI !== 'undefined' && typeof UI.InfoMessage === 'function') { let hotkeyDisplay = currentSettings.toggleKeyChar; if (currentSettings.requiredCtrl) hotkeyDisplay = 'Strg + ' + hotkeyDisplay; if (currentSettings.requiredAlt) hotkeyDisplay = 'Alt + ' + hotkeyDisplay; if (currentSettings.requiredShift) hotkeyDisplay = 'Shift + ' + hotkeyDisplay; hotkeyDisplay = hotkeyDisplay.replace(/\s\+\s$/, ''); UI.InfoMessage('Auto-Action gestartet! (Hotkey: ' + hotkeyDisplay + ' zum Stoppen)', 3000); } noFarmButtonsDetected = false; } updateUIStatus(); // Aktualisiert auch den Tab-Titel und Buttons }; // --- PRÄZISER SELEKTOR FÜR BELIEBIGEN FARMGOD BUTTON --- const FARM_BUTTON_SELECTOR = 'a.farmGod_icon'; let customDialogElement = null; // --- Einstellungsdialog --- function openSettingsDialog() { if (customDialogElement) { customDialogElement.remove(); customDialogElement = null; } const dialogContentHtml = `
| Hotkey (Taste) | |
|---|---|
| Benötigte Tasten |
|
| Min. Abstand (ms) | |
| Max. Abstand (ms) | |
| Botschutz pausieren | Bei Botschutz-Abfrage pausieren |
| Botschutz-Ton |
|