// ==UserScript== // @name MWI-AutoCombat // @name:zh-CN MWI自动战斗助手 // @namespace https://github.com/CYR2077 // @version 1.0 // @description Auto-manage game queue(自动9战) // @author CYR2077 // @license GPL3 // @match https://www.milkywayidle.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com // @grant GM_setValue // @grant GM_getValue // @downloadURL none // ==/UserScript== /** * 关于使用本插件可能存在的脚本行为说明: * * 《游戏规则》 * * 4.机器人、脚本和扩展 * * 4.1禁止机器人: 请勿使用任何自动化程序代替你操作游戏。 * 4.2脚本和扩展: 任何脚本或扩展程序都不得为玩家执行任何操作(向服务器发送任何请求), 仅限使用于显示信息或改进用户界面 (例如: 显示战斗摘要、跟踪掉落、将按钮移动到不同位置)。 * * 请仔细阅读游戏规则条款后,再选择是否安装使用本插件,谢谢! */ (function (workerScript) { if (!/MSIE 10/i.test (navigator.userAgent)) { try { var blob = new Blob (["\ var fakeIdToId = {};\ onmessage = function (event) {\ var data = event.data,\ name = data.name,\ fakeId = data.fakeId,\ time;\ if(data.hasOwnProperty('time')) {\ time = data.time;\ }\ switch (name) {\ case 'setInterval':\ fakeIdToId[fakeId] = setInterval(function () {\ postMessage({fakeId: fakeId});\ }, time);\ break;\ case 'clearInterval':\ if (fakeIdToId.hasOwnProperty (fakeId)) {\ clearInterval(fakeIdToId[fakeId]);\ delete fakeIdToId[fakeId];\ }\ break;\ case 'setTimeout':\ fakeIdToId[fakeId] = setTimeout(function () {\ postMessage({fakeId: fakeId});\ if (fakeIdToId.hasOwnProperty (fakeId)) {\ delete fakeIdToId[fakeId];\ }\ }, time);\ break;\ case 'clearTimeout':\ if (fakeIdToId.hasOwnProperty (fakeId)) {\ clearTimeout(fakeIdToId[fakeId]);\ delete fakeIdToId[fakeId];\ }\ break;\ }\ }\ "]); // Obtain a blob URL reference to our worker 'file'. workerScript = window.URL.createObjectURL(blob); } catch (error) { /* Blob is not supported, use external script instead */ } } var worker, fakeIdToCallback = {}, lastFakeId = 0, maxFakeId = 0x7FFFFFFF, // 2 ^ 31 - 1, 31 bit, positive values of signed 32 bit integer logPrefix = 'HackTimer.js by turuslan: '; if (typeof (Worker) !== 'undefined') { function getFakeId () { do { if (lastFakeId == maxFakeId) { lastFakeId = 0; } else { lastFakeId ++; } } while (fakeIdToCallback.hasOwnProperty (lastFakeId)); return lastFakeId; } try { worker = new Worker (workerScript); window.setInterval = function (callback, time /* , parameters */) { var fakeId = getFakeId (); fakeIdToCallback[fakeId] = { callback: callback, parameters: Array.prototype.slice.call(arguments, 2) }; worker.postMessage ({ name: 'setInterval', fakeId: fakeId, time: time }); return fakeId; }; window.clearInterval = function (fakeId) { if (fakeIdToCallback.hasOwnProperty(fakeId)) { delete fakeIdToCallback[fakeId]; worker.postMessage ({ name: 'clearInterval', fakeId: fakeId }); } }; window.setTimeout = function (callback, time /* , parameters */) { var fakeId = getFakeId (); fakeIdToCallback[fakeId] = { callback: callback, parameters: Array.prototype.slice.call(arguments, 2), isTimeout: true }; worker.postMessage ({ name: 'setTimeout', fakeId: fakeId, time: time }); return fakeId; }; window.clearTimeout = function (fakeId) { if (fakeIdToCallback.hasOwnProperty(fakeId)) { delete fakeIdToCallback[fakeId]; worker.postMessage ({ name: 'clearTimeout', fakeId: fakeId }); } }; worker.onmessage = function (event) { var data = event.data, fakeId = data.fakeId, request, parameters, callback; if (fakeIdToCallback.hasOwnProperty(fakeId)) { request = fakeIdToCallback[fakeId]; callback = request.callback; parameters = request.parameters; if (request.hasOwnProperty ('isTimeout') && request.isTimeout) { delete fakeIdToCallback[fakeId]; } } if (typeof (callback) === 'string') { try { callback = new Function (callback); } catch (error) { console.log (logPrefix + 'Error parsing callback code string: ', error); } } if (typeof (callback) === 'function') { callback.apply (window, parameters); } }; worker.onerror = function (event) { console.log (event); }; } catch (error) { console.log (logPrefix + 'Initialisation failed'); console.error (error); } } else { console.log (logPrefix + 'Initialisation failed - HTML5 Web Worker is not supported'); } }) ('HackTimerWorker.js'); (function () { 'use strict'; // Language detection and internationalization const isChineseUser = () => { const lang = navigator.language.toLowerCase(); return lang.startsWith('zh'); }; const translations = { zh: { title: '自动战斗助手', selectTask: '选择任务:', executionCount: '执行次数:', startAuto: '开始挂机', stopAuto: '停止挂机', noTasksFound: '未找到任务 (请初始化)', initializeTasks: '初始化战斗任务列表', status: { waitingToStart: '状态: 等待开始', invalidNumber: '请输入1-9999999999之间的整数!', invalidCountSet: '执行次数无效,已设置为1次', startingAuto: '开始挂机', times: '次', stopped: '已停止挂机', addedToQueue: '已添加到队列', addToQueueFailed: '添加到队列失败', queueNotFull: '队列未满,添加新任务', queueStatus: '队列状态', queueFull: '队列已满,等待队列消化', executionError: '执行出错', timeout: '超时,停止执行' } }, en: { title: 'MWI-AutoCombat', selectTask: 'Select Task:', executionCount: 'Execution Count:', startAuto: 'Start Auto', stopAuto: 'Stop Auto', noTasksFound: 'No tasks found (Please initialize)', initializeTasks: 'Initialize Battle Task List', status: { waitingToStart: 'Status: Waiting to start', invalidNumber: 'Please enter an integer between 1-9999999999!', invalidCountSet: 'Invalid execution count, set to 1', startingAuto: 'Starting automation', times: 'times', stopped: 'Automation stopped', addedToQueue: 'Added to queue', addToQueueFailed: 'Failed to add to queue', queueNotFull: 'Queue not full, adding new task', queueStatus: 'Queue status', queueFull: 'Queue is full, waiting for queue to process', executionError: 'Execution error', timeout: 'Timeout, stopping execution' } } }; const t = translations[isChineseUser() ? 'zh' : 'en']; let isRunning = false; let retryCount = 0; let currentConfig = { planetIndex: 0, battleCount: 5, retryDelay: 30000, maxRetries: 30 }; // Drag-related variables let isDragging = false; let dragOffset = { x: 0, y: 0 }; // Storage keys const STORAGE_KEYS = { PLANET_INDEX: 'automation_planet_index', BATTLE_COUNT: 'automation_battle_count' }; // Save settings to storage function saveSettings() { const planetSelect = document.getElementById('planet-select'); const battleInput = document.getElementById('battle-count'); if (planetSelect && battleInput) { GM_setValue(STORAGE_KEYS.PLANET_INDEX, planetSelect.value); GM_setValue(STORAGE_KEYS.BATTLE_COUNT, battleInput.value); } } // Load settings from storage function loadSettings() { const savedPlanetIndex = GM_getValue(STORAGE_KEYS.PLANET_INDEX, '0'); const savedBattleCount = GM_getValue(STORAGE_KEYS.BATTLE_COUNT, '9'); return { planetIndex: savedPlanetIndex, battleCount: savedBattleCount }; } // Apply saved settings to UI function applySettings() { const settings = loadSettings(); const planetSelect = document.getElementById('planet-select'); const battleInput = document.getElementById('battle-count'); if (planetSelect && battleInput) { // Restore execution count battleInput.value = settings.battleCount; // Restore planet selection (need to wait for options to load) if (planetSelect.options.length > 0) { const planetIndex = parseInt(settings.planetIndex); if (planetIndex < planetSelect.options.length) { planetSelect.value = settings.planetIndex; } } } } function createUI() { const container = document.createElement('div'); container.id = 'queue-automation-panel'; container.style.cssText = ` position: fixed; top: 20px; right: 20px; width: 300px; background: rgba(44, 62, 80, 0.95); color: white; border-radius: 10px; padding: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.3); z-index: 10000; font-family: Arial, sans-serif; font-size: 14px; backdrop-filter: blur(5px); transition: opacity 0.3s ease; `; const titleBar = document.createElement('div'); titleBar.id = 'title-bar'; titleBar.style.cssText = ` display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; cursor: move; user-select: none; `; const title = document.createElement('h3'); title.id = 'panel-title'; title.textContent = t.title; title.style.cssText = ` margin: 0; color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; flex: 1; text-align: center; cursor: move; `; const toggleButton = document.createElement('button'); toggleButton.id = 'toggle-button'; toggleButton.textContent = '−'; toggleButton.style.cssText = ` width: 25px; height: 25px; border: none; border-radius: 50%; background: #e74c3c; color: white; cursor: pointer; font-size: 16px; line-height: 1; margin-left: 10px; flex-shrink: 0; transition: filter 0.3s ease; `; toggleButton.addEventListener('mouseenter', () => { toggleButton.style.filter = 'brightness(110%)'; }); toggleButton.addEventListener('mouseleave', () => { toggleButton.style.filter = 'brightness(100%)'; }); titleBar.appendChild(title); titleBar.appendChild(toggleButton); const content = document.createElement('div'); content.id = 'panel-content'; const planetLabel = document.createElement('label'); planetLabel.textContent = t.selectTask; planetLabel.style.cssText = 'display: block; margin-bottom: 5px; font-weight: bold;'; const planetSelect = document.createElement('select'); planetSelect.id = 'planet-select'; planetSelect.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 15px; border: none; border-radius: 5px; background: rgba(52, 73, 94, 0.8); color: white; font-size: 14px; `; const battleLabel = document.createElement('label'); battleLabel.textContent = t.executionCount; battleLabel.style.cssText = 'display: block; margin-bottom: 5px; font-weight: bold;'; const battleInput = document.createElement('input'); battleInput.id = 'battle-count'; battleInput.type = 'number'; battleInput.value = '9'; battleInput.min = '1'; battleInput.max = '9999999999'; battleInput.step = '1'; battleInput.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 15px; border: none; border-radius: 5px; background: rgba(52, 73, 94, 0.8); color: white; font-size: 14px; box-sizing: border-box; `; // Prevent decimal input battleInput.addEventListener('keydown', function(e) { if (e.key === '.' || e.key === 'e' || e.key === '-') { e.preventDefault(); } }); const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = 'display: flex; gap: 10px; margin-bottom: 15px;'; const startButton = document.createElement('button'); startButton.id = 'start-button'; startButton.textContent = t.startAuto; startButton.style.cssText = ` flex: 1; padding: 10px; border: none; border-radius: 5px; background: #27ae60; color: white; font-size: 14px; font-weight: bold; cursor: pointer; transition: filter 0.3s ease, opacity 0.3s ease; `; const stopButton = document.createElement('button'); stopButton.id = 'stop-button'; stopButton.textContent = t.stopAuto; stopButton.disabled = true; stopButton.style.cssText = ` flex: 1; padding: 10px; border: none; border-radius: 5px; background: #e74c3c; color: white; font-size: 14px; font-weight: bold; cursor: pointer; transition: filter 0.3s ease, opacity 0.3s ease; opacity: 0.5; `; // Add hover effects [startButton, stopButton].forEach(button => { button.addEventListener('mouseenter', () => { if (!button.disabled) { button.style.filter = 'brightness(110%)'; } }); button.addEventListener('mouseleave', () => { button.style.filter = 'brightness(100%)'; }); }); const statusDiv = document.createElement('div'); statusDiv.id = 'status-display'; statusDiv.style.cssText = ` background: rgba(52, 73, 94, 0.8); padding: 10px; border-radius: 5px; margin-bottom: 10px; height: 120px; font-size: 12px; line-height: 1.4; overflow-y: auto; `; statusDiv.innerHTML = `