// ==UserScript== // @name 乐斗辅助 // @namespace http://tampermonkey.net/ // @version 1.8.0 // @description 提供系统繁忙监控、定时刷新、碎片监控、侠客岛任务、自动抢地盘、武器血量高亮、黄历、购物道具仓库余量显示、方向键控制、定时任务、文字游戏 // @author xiong1136108122 // @match https://dld.qzapp.z.qq.com/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js // @connect qzapp.z.qq.com // @connect fight.pet.qq.com // @connect dld.qzapp.z.qq.com // ==/UserScript== (function() { 'use strict'; // 默认高亮关键字 const DEFAULT_HIGHLIGHT_KEYWORDS = [ '帮派商会', '帮派祭坛', '全民乱斗', '华山论剑', '竞技场', '吉利兑', '飞升大作战', '群侠', '祝福宝库', '远方祝福', '大侠回归三重好礼', '侠客岛', '任务', '九宫宝库', '符石宝箱', '年兽大作战', '喜从天降', '春联大赛', '新元婴神器', '徽章优惠', '乐斗驿站', '乐斗游记' ]; // 默认武器高亮关键词 const DEFAULT_WEAPON_KEYWORDS = [ '神·霸皇', '盘古开天斧', '神·大力神杯', '神·雷神之锤', '神·炼狱加特林', '加特林', '神·死寂', '死神之镰', '神·无限板砖', '神·埃辛诺斯战刃', '神·命运之枪', '神·龙雀', '神·马格南左轮', '神·月光炮', '神·电饭煲', '神·星之杖', '神·死亡笔记', '生死簿', '神·冈格尼尔', '神·可乐切割枪', '神·无敌飞鞋', '神·花仙子' ]; // 获取高亮关键字,确保有默认值 function getHighlightKeywords() { let keywords = GM_getValue('highlightKeywords', null); if (keywords === null || keywords === undefined || (Array.isArray(keywords) && keywords.length === 0)) { keywords = [...DEFAULT_HIGHLIGHT_KEYWORDS]; GM_setValue('highlightKeywords', keywords); } return keywords; } // 获取武器高亮关键字 function getWeaponHighlightKeywords() { let keywords = GM_getValue('weaponHighlightKeywords', null); if (keywords === null || keywords === undefined || (Array.isArray(keywords) && keywords.length === 0)) { keywords = [...DEFAULT_WEAPON_KEYWORDS]; GM_setValue('weaponHighlightKeywords', keywords); } return keywords; } // 配置存储 const CONFIG = { systemBusy: { enabled: GM_getValue('systemBusyEnabled', true), targetText: GM_getValue('systemBusyTargetText', '系统繁忙'), checkInterval: GM_getValue('systemBusyCheckInterval', 100), refreshCooldown: GM_getValue('systemBusyRefreshCooldown', 2000) }, autoRefresh: { enabled: GM_getValue('autoRefreshEnabled', false), interval: GM_getValue('autoRefreshInterval', 2), stopKeywords: GM_getValue('autoRefreshStopKeywords', ['不足','不够']) }, fragmentMonitor: { enabled: GM_getValue('fragmentMonitorEnabled', false), checkUrl: 'https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?zapp_uin=&B_UID=0&sid=&channel=0&g_ut=1&cmd=newAct&subtype=154', jumpUrl: 'https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?zapp_uin=&B_UID=0&sid=&channel=0&g_ut=1&cmd=newAct&subtype=155', triggerKeywords: GM_getValue('fragmentTriggerKeywords', ['王重阳', '王处一']), stopKeywords: GM_getValue('fragmentStopKeywords', ['数量:0', '碎片*5']), interval: GM_getValue('fragmentMonitorInterval', 2) }, knightIsland: { enabled: GM_getValue('knightIslandEnabled', true), checkInterval: GM_getValue('knightIslandCheckInterval', 90) }, territoryGrabber: { enabled: GM_getValue('territoryGrabberEnabled', false), targetLevel: GM_getValue('territoryGrabberTargetLevel', 30), retryLimit: GM_getValue('territoryGrabberRetryLimit', 3), baseDelay: GM_getValue('territoryGrabberBaseDelay', 2000), maxRandomDelay: GM_getValue('territoryGrabberMaxRandomDelay', 3000) }, textGame: { enabled: GM_getValue('textGameEnabled', true), highlightKeywords: getHighlightKeywords(), weaponHighlightKeywords: getWeaponHighlightKeywords() }, goodsStock: { enabled: GM_getValue('goodsStockEnabled', true) }, directionKey: { enabled: GM_getValue('directionKeyEnabled', true), scrollAmount: GM_getValue('directionKeyScrollAmount', 200), fastScrollAmount: GM_getValue('directionKeyFastScrollAmount', 300), enableShiftScroll: GM_getValue('directionKeyEnableShiftScroll', true), ignoreInputs: GM_getValue('directionKeyIgnoreInputs', true), smoothScroll: GM_getValue('directionKeySmoothScroll', true) }, scheduledTasks: { enabled: GM_getValue('scheduledTasksEnabled', false), tasks: GM_getValue('scheduledTasks', [ { name: '定时任务', url: ' ', time: '06:00:01', count: 3, interval: 1000, enabled: true } ]) } }; // 定时器变量 let module2Timer = null; let module3Timer = null; let territoryGrabberRetryCount = 0; let directionKeyLastScrollTime = 0; /* ========== 文字游戏模块(高亮+替换) ========== */ function applyTextReplacements(text) { if (!CONFIG.textGame.enabled) return text; let result = text; // 1. 删除指定文字 if (CONFIG.textGame.removeWords && CONFIG.textGame.removeWords.length > 0) { CONFIG.textGame.removeWords.forEach(word => { if (word && word.trim()) { const regex = new RegExp(word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'); result = result.replace(regex, ''); } }); } // 2. 替换指定文字 if (CONFIG.textGame.replaceRules && CONFIG.textGame.replaceRules.length > 0) { CONFIG.textGame.replaceRules.forEach(rule => { if (rule.from && rule.from.trim()) { const regex = new RegExp(rule.from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'); result = result.replace(regex, rule.to || ''); } }); } return result; } function saveTextGameSettings() { // 保存高亮关键字 const highlightInput = document.getElementById('highlightKeywords').value; const highlightKeywords = highlightInput.split(/[,,]/) .map(s => s.trim()) .filter(s => s); CONFIG.textGame.highlightKeywords = highlightKeywords; GM_setValue('highlightKeywords', highlightKeywords); // 保存武器高亮关键字 const weaponHighlightInput = document.getElementById('weaponHighlightKeywords').value; const weaponKeywords = weaponHighlightInput.split(/[,,]/) .map(s => s.trim()) .filter(s => s); CONFIG.textGame.weaponHighlightKeywords = weaponKeywords; GM_setValue('weaponHighlightKeywords', weaponKeywords); // 重新应用文字游戏 if (CONFIG.textGame.enabled) { applyTextGame(); } } // 应用文字游戏(高亮+替换) function applyTextGame() { if (!CONFIG.textGame.enabled) return; GM_addStyle(` .tm-hp-change { display: inline; white-space: nowrap; } .tm-hp-plus { color: #00aa00; font-weight: bold; } .tm-hp-minus { color: #ff0000; font-weight: bold; } .tm-key-weapon { color: #aa00aa; font-weight: bold; } .tm-keyword-bold { color: #1ba784; font-weight: bold; } `); const hpRegexChange = /(HP[+-]\d+)/g; const hpRegexRemain = /(HP余\d+)/g; const spiralRegex = /(反弹给对方(\d+)的伤害!)/g; // 动态构建武器正则 const weaponKeywords = CONFIG.textGame.weaponHighlightKeywords || []; const weaponRegex = weaponKeywords.length ? new RegExp(`(${weaponKeywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')})`, 'g') : /(?!)/; // 使用用户自定义的关键字 const userKeywords = CONFIG.textGame.highlightKeywords || []; // 动态添加关键字 const keywordSet = new Set(userKeywords); if (document.body.innerText.includes("至尊传功")) { keywordSet.add('经脉'); } if (document.body.innerText.includes("军需处")) { keywordSet.add('五行'); } if (document.body.innerText.includes("达人特惠")) { keywordSet.add('续费达人'); } if (document.body.innerText.includes("藏经阁")) { keywordSet.add('兵法'); } const keywordRegex = new RegExp([...keywordSet].map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g'); const safeReplace = (text) => { // 先进行文本替换(删除和替换) text = applyTextReplacements(text); // 然后进行高亮处理 if (document.body.innerText.includes("【大乐斗】") || document.body.innerText.includes("Q宠大乐斗")) { text = text.replace(keywordRegex, (keyword) => `${keyword}` ); } text = text.replace(weaponRegex, (weapon) => `${weapon}` ); text = text.replace(hpRegexChange, (change) => `${change}` ); text = text.replace(hpRegexRemain, (remain) => `${remain}` ); text = text.replace(spiralRegex, (fullMatch, fullText, damage) => fullText.replace(damage, `${damage}`) ); return text; }; const processNode = (node) => { // 跳过控制面板及其子元素 if (node.id === 'gameHelperPanel' || node.closest?.('#gameHelperPanel')) { return; } // 跳过所有表单元素及其内部节点 if (node.nodeType === Node.ELEMENT_NODE) { const tagName = node.tagName.toLowerCase(); if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') { return; // 直接跳过整个表单元素,不处理其内部 } } if (node.nodeType === Node.TEXT_NODE && !node.parentNode.classList.contains('tm-hp-processed') && (hpRegexChange.test(node.nodeValue) || hpRegexRemain.test(node.nodeValue) || weaponRegex.test(node.nodeValue) || spiralRegex.test(node.nodeValue) || keywordRegex.test(node.nodeValue))) { const wrapper = document.createElement('span'); wrapper.className = 'tm-hp-processed'; wrapper.innerHTML = safeReplace(node.nodeValue); node.parentNode.replaceChild(wrapper, node); } else if (node.nodeType === Node.ELEMENT_NODE && !node.classList.contains('tm-hp-processed')) { Array.from(node.childNodes).forEach(processNode); } }; processNode(document.body); } /* ========== 定时任务模块 ========== */ function sendScheduledRequest(task, index) { return new Promise((resolve) => { GM_xmlhttpRequest({ method: 'GET', url: task.url, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': '*/*' }, timeout: 8000, onload: function(response) { Mylog(`[定时任务 ${task.name}] 请求 ${index}/${task.count} - 状态: ${response.status}`); resolve({ success: response.status === 200, status: response.status }); }, onerror: function(error) { Mylog(`[定时任务 ${task.name}] 请求 ${index}/${task.count} 失败: ${error}`); resolve({ success: false, error: error }); }, ontimeout: function() { Mylog(`[定时任务 ${task.name}] 请求 ${index}/${task.count} 超时`); resolve({ success: false, error: 'timeout' }); } }); }); } async function executeScheduledTask(task) { if (!task.enabled) return; const startTime = new Date(); Mylog(`[定时任务 ${task.name}] 开始执行 ${task.count} 次请求 (${startTime.toLocaleString()})`); const results = []; for (let i = 1; i <= task.count; i++) { if (i > 1) { await new Promise(resolve => setTimeout(resolve, task.interval)); } const result = await sendScheduledRequest(task, i); results.push(result); } const successCount = results.filter(r => r.success).length; const endTime = new Date(); const duration = endTime - startTime; task.lastExecution = endTime.toISOString(); GM_setValue(`task_lastExecution_${task.name}`, task.lastExecution); Mylog(`[定时任务 ${task.name}] 执行完成,成功 ${successCount}/${task.count} 次,耗时 ${duration}ms`); return results; } function checkTaskStatus() { if (!CONFIG.scheduledTasks.enabled) return; const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); CONFIG.scheduledTasks.tasks.forEach(task => { if (task.enabled && task.lastExecution) { const lastExec = new Date(task.lastExecution); const lastExecDay = new Date(lastExec.getFullYear(), lastExec.getMonth(), lastExec.getDate()); if (lastExecDay.getTime() !== today.getTime()) { const [hours, minutes] = task.time.split(':').map(Number); const taskTime = new Date(today); taskTime.setHours(hours, minutes, 0, 0); if (now - taskTime > 10 * 60 * 1000) { Mylog(`[定时任务 ${task.name}] 警告:今天可能错过了执行时间`); } } } }); } function formatDelayTime(ms) { const totalSeconds = Math.floor(ms / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; if (hours > 0) { return `${hours}小时${minutes}分钟${seconds}秒`; } else if (minutes > 0) { return `${minutes}分钟${seconds}秒`; } else { return `${seconds}秒`; } } function setupScheduledTaskTimer(task) { if (task.timerId) { clearTimeout(task.timerId); task.timerId = null; } if (!task.enabled || !task.time ) { Mylog(`[定时任务 ${task.name}] 时间格式无效或被禁用: ${task.time}`); return; } const delay = calculateExactDelay(task.time); if (delay < 0 || delay > 24 * 60 * 60 * 1000) { Mylog(`[定时任务 ${task.name}] 时间计算错误: ${task.time}, delay=${delay}ms`); return; } const nextTime = new Date(Date.now() + delay); Mylog(`[定时任务 ${task.name}] 下次执行: ${nextTime.toLocaleString()} (${formatDelayTime(delay)})`); const startTime = Date.now(); task.timerId = setTimeout(async () => { const actualDelay = Date.now() - startTime; const deviation = actualDelay - delay; if (Math.abs(deviation) > 1000) { Mylog(`[定时任务 ${task.name}] 定时器偏差较大: ${deviation}ms`); } Mylog(`[定时任务 ${task.name}] 到达预定时间 ${task.time},开始执行...`); try { await executeScheduledTask(task); Mylog(`[定时任务 ${task.name}] 执行完成`); } catch (error) { Mylog(`[定时任务 ${task.name}] 执行出错: ${error}`); } scheduleNextExecution(task); }, delay); } function calculateExactDelay(targetTime) { const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const [hours, minutes, seconds] = targetTime.split(':').map(Number); const targetToday = new Date(today); targetToday.setHours(hours, minutes, seconds, 0); const targetTomorrow = new Date(today); targetTomorrow.setDate(targetTomorrow.getDate() + 1); targetTomorrow.setHours(hours, minutes, seconds, 0); let target = targetToday; if (now > targetToday) { target = targetTomorrow; } return target.getTime() - now.getTime(); } function scheduleNextExecution(task) { if (task.timerId) { clearTimeout(task.timerId); task.timerId = null; } setTimeout(() => { setupScheduledTaskTimer(task); }, 1000); } function initScheduledTasks() { if (!CONFIG.scheduledTasks.enabled) return; Mylog(`[定时任务] 初始化,共 ${CONFIG.scheduledTasks.tasks.length} 个任务`); stopAllScheduledTasks(); CONFIG.scheduledTasks.tasks.forEach(task => { setupScheduledTaskTimer(task); }); } function setupDailyCheck() { const checkTime = '02:00:00'; const checkDelay = calculateExactDelay(checkTime); setTimeout(() => { Mylog('[定时任务] 执行每日状态检查'); checkAndRescheduleTasks(); setupDailyCheck(); }, checkDelay); } function checkAndRescheduleTasks() { if (!CONFIG.scheduledTasks.enabled) return; const now = new Date(); const currentHour = now.getHours(); const currentMinute = now.getMinutes(); CONFIG.scheduledTasks.tasks.forEach(task => { if (task.enabled && task.time) { const [hours, minutes] = task.time.split(':').map(Number); const taskTimeMinutes = hours * 60 + minutes; const currentTimeMinutes = currentHour * 60 + currentMinute; if (taskTimeMinutes < currentTimeMinutes && (currentTimeMinutes - taskTimeMinutes) <= 120) { Mylog(`[定时任务 ${task.name}] 可能错过了今天的执行,重新安排`); if (task.timerId) { clearTimeout(task.timerId); task.timerId = null; } setupScheduledTaskTimer(task); } } }); } function stopAllScheduledTasks() { CONFIG.scheduledTasks.tasks.forEach(task => { if (task.timerId) { clearTimeout(task.timerId); task.timerId = null; } }); Mylog('[定时任务] 已停止所有定时任务'); } function saveScheduledTaskSettings() { try { const tasks = []; document.querySelectorAll('.scheduled-task-item').forEach((item, index) => { const intervalInput = item.querySelector('.task-interval').value; const intervalInMs = Math.max(100, Math.floor(parseFloat(intervalInput) * 1000)) || 1000; const task = { name: item.querySelector('.task-name').value.trim() || `任务${index + 1}`, url: item.querySelector('.task-url').value.trim(), time: item.querySelector('.task-time').value, count: parseInt(item.querySelector('.task-count').value) || 1, interval: intervalInMs, enabled: item.querySelector('.task-enabled').checked }; if (task.url && task.time) { tasks.push(task); } }); CONFIG.scheduledTasks.tasks = tasks; GM_setValue('scheduledTasks', tasks); updateTaskCount(); const taskStatus = document.getElementById('taskStatus'); if (taskStatus) { taskStatus.textContent = `已保存 ${tasks.length} 个任务`; taskStatus.style.color = "#4CAF50"; } if (CONFIG.scheduledTasks.enabled) { initScheduledTasks(); } Mylog(`[定时任务] 设置已保存,共 ${tasks.length} 个任务`); } catch (error) { console.error("[定时任务] 保存失败:", error); Mylog("[定时任务] 保存失败: " + error.message); const taskStatus = document.getElementById('taskStatus'); if (taskStatus) { taskStatus.textContent = "保存失败"; taskStatus.style.color = "#ff4444"; } } } async function executeTaskNow(taskName) { const task = CONFIG.scheduledTasks.tasks.find(t => t.name === taskName); if (task) { Mylog(`[定时任务] 手动执行: ${taskName}`); return await executeScheduledTask(task); } else { Mylog(`[定时任务] 未找到任务: ${taskName}`); return null; } } function testFirstTask() { if (CONFIG.scheduledTasks.tasks.length > 0) { const firstTask = CONFIG.scheduledTasks.tasks[0]; Mylog(`[定时任务] 测试执行: ${firstTask.name}`); executeScheduledTask(firstTask); } else { Mylog('[定时任务] 没有可测试的任务'); } } function addNewTask() { const tasksContainer = document.getElementById('scheduledTasksList'); if (!tasksContainer) return; const taskIndex = tasksContainer.children.length + 1; const taskItem = document.createElement('div'); taskItem.className = 'scheduled-task-item'; taskItem.innerHTML = `
`; tasksContainer.appendChild(taskItem); taskItem.querySelector('.task-remove').addEventListener('click', function() { removeTaskItem(taskItem); }); const inputs = taskItem.querySelectorAll('input'); inputs.forEach(input => { input.addEventListener('change', function() { showUnsavedChanges(); }); }); setTimeout(saveScheduledTaskSettings, 100); updateTaskCount(); Mylog("[定时任务] 已添加新任务"); } function removeTaskItem(taskItem) { const tasksContainer = document.getElementById('scheduledTasksList'); if (!tasksContainer) return; if (tasksContainer.children.length > 1) { const taskName = taskItem.querySelector('.task-name').value; taskItem.remove(); Mylog(`[定时任务] 已删除任务: ${taskName}`); updateTaskCount(); setTimeout(saveScheduledTaskSettings, 100); } else { alert('至少需要保留一个任务'); } } function loadScheduledTasksUI() { const tasksList = document.getElementById('scheduledTasksList'); if (!tasksList) return; tasksList.innerHTML = ''; if (CONFIG.scheduledTasks.tasks.length === 0) { CONFIG.scheduledTasks.tasks = [{ name: '凌晨任务', url: 'https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?zapp_uin=&sid=&channel=0&g_ut=1&cmd=notice&op=choice&optid=1', time: '00:00:01', count: 3, interval: 1000, enabled: true }]; GM_setValue('scheduledTasks', CONFIG.scheduledTasks.tasks); } CONFIG.scheduledTasks.tasks.forEach((task, index) => { const taskItem = document.createElement('div'); taskItem.className = 'scheduled-task-item'; const intervalInSeconds = typeof task.interval === 'number' ? (task.interval >= 100 ? task.interval / 1000 : task.interval) : 1; taskItem.innerHTML = `
`; tasksList.appendChild(taskItem); taskItem.querySelector('.task-remove').addEventListener('click', function() { removeTaskItem(taskItem); }); const inputs = taskItem.querySelectorAll('input'); inputs.forEach(input => { input.addEventListener('change', function() { showUnsavedChanges(); }); }); }); updateTaskCount(); } function updateTaskCount() { const taskCountBadge = document.getElementById('taskCountBadge'); const tasksList = document.getElementById('scheduledTasksList'); if (taskCountBadge && tasksList) { const count = tasksList.children.length; taskCountBadge.textContent = `(${count})`; taskCountBadge.style.color = count > 0 ? '#4CAF50' : '#888'; } const taskStatus = document.getElementById('taskStatus'); if (taskStatus) { taskStatus.textContent = `当前有 ${tasksList ? tasksList.children.length : 0} 个任务`; taskStatus.style.color = "#888"; } } function showUnsavedChanges() { const taskStatus = document.getElementById('taskStatus'); if (taskStatus) { taskStatus.textContent = "有未保存的更改"; taskStatus.style.color = "#FFA500"; } clearTimeout(window.taskSaveTimer); window.taskSaveTimer = setTimeout(saveScheduledTaskSettings, 1500); } /* ========== 方向键控制功能 ========== */ function initDirectionKeyControl() { if (!CONFIG.directionKey.enabled) return; document.addEventListener('keydown', handleDirectionKeyDown, true); Mylog("[方向键控制] 已启用 - 上下滚动,左右前进后退"); } function isInInputElement(element) { const inputTypes = ['input', 'textarea', 'select']; const contentEditable = element.isContentEditable || element.getAttribute('contenteditable') === 'true'; if (contentEditable) return true; const tagName = element.tagName.toLowerCase(); if (inputTypes.includes(tagName)) { if (tagName === 'input') { const type = element.type.toLowerCase(); const editableTypes = ['text', 'password', 'email', 'search', 'tel', 'url', 'number']; return editableTypes.includes(type); } return true; } return false; } function handleDirectionKeyDown(event) { if (!CONFIG.directionKey.enabled) return; if (CONFIG.directionKey.ignoreInputs && isInInputElement(event.target)) { return; } const { key, shiftKey } = event; if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(key)) { return; } event.preventDefault(); event.stopPropagation(); const now = Date.now(); const scrollDelay = now - directionKeyLastScrollTime; if (scrollDelay < 50) return; directionKeyLastScrollTime = now; let scrollAmount = CONFIG.directionKey.scrollAmount; if (shiftKey && CONFIG.directionKey.enableShiftScroll) { scrollAmount = CONFIG.directionKey.fastScrollAmount; } const scrollOptions = CONFIG.directionKey.smoothScroll ? { behavior: 'smooth' } : {}; switch (key) { case 'ArrowUp': window.scrollBy({ top: -scrollAmount, ...scrollOptions }); break; case 'ArrowDown': window.scrollBy({ top: scrollAmount, ...scrollOptions }); break; case 'ArrowLeft': if (window.history.length > 1) { window.history.back(); } break; case 'ArrowRight': window.history.forward(); break; } } /* ========== 模块1:系统繁忙监控 ========== */ let systemBusyMonitorInterval = null; let lastRefreshTime = 0; function startSystemBusyMonitor() { stopSystemBusyMonitor(); Mylog("[系统繁忙监控] 已启动,正在检测 '" + CONFIG.systemBusy.targetText + "'..."); systemBusyMonitorInterval = setInterval(() => { const now = Date.now(); if (now - lastRefreshTime < CONFIG.systemBusy.refreshCooldown) { return; } if (document.body.innerText.includes(CONFIG.systemBusy.targetText)) { Mylog("[系统繁忙监控] 检测到 '" + CONFIG.systemBusy.targetText + "',准备刷新页面..."); lastRefreshTime = now; location.reload(); } }, CONFIG.systemBusy.checkInterval); } function stopSystemBusyMonitor() { if (systemBusyMonitorInterval) { clearInterval(systemBusyMonitorInterval); systemBusyMonitorInterval = null; } } function saveSystemBusySettings() { const targetText = document.getElementById('systemBusyTargetText').value.trim(); const checkInterval = parseInt(document.getElementById('systemBusyCheckInterval').value); const refreshCooldown = parseInt(document.getElementById('systemBusyRefreshCooldown').value); CONFIG.systemBusy.targetText = targetText; CONFIG.systemBusy.checkInterval = checkInterval; CONFIG.systemBusy.refreshCooldown = refreshCooldown; GM_setValue('systemBusyTargetText', targetText); GM_setValue('systemBusyCheckInterval', checkInterval); GM_setValue('systemBusyRefreshCooldown', refreshCooldown); if (CONFIG.systemBusy.enabled) { stopSystemBusyMonitor(); startSystemBusyMonitor(); } } /* ========== 模块2:定时刷新功能 ========== */ function startAutoRefresh() { stopAutoRefresh(); const interval = CONFIG.autoRefresh.interval * 1000; module2Timer = setInterval(() => { const bodyText = getPageText(); const shouldStop = CONFIG.autoRefresh.stopKeywords.some( keyword => bodyText.includes(keyword) ); if (shouldStop) { stopAutoRefresh(); CONFIG.autoRefresh.enabled = false; GM_setValue('autoRefreshEnabled', false); document.getElementById('autoRefreshToggle').checked = false; Mylog("[定时刷新] 已检测到停止关键词,自动关闭功能"); } else { Mylog("[定时刷新] 执行定时刷新"); window.location.reload(); } }, interval); } function stopAutoRefresh() { if (module2Timer) { clearInterval(module2Timer); module2Timer = null; } } function saveAutoRefreshSettings() { const interval = parseFloat(document.getElementById('autoRefreshInterval').value); const stopKeywords = document.getElementById('autoRefreshStopKeywords').value .split(/[,,]/) .map(s => s.trim()) .filter(s => s); CONFIG.autoRefresh.interval = interval; CONFIG.autoRefresh.stopKeywords = stopKeywords; GM_setValue('autoRefreshInterval', interval); GM_setValue('autoRefreshStopKeywords', stopKeywords); if (CONFIG.autoRefresh.enabled) { stopAutoRefresh(); startAutoRefresh(); } } function getPageText() { return document.body.innerText || document.body.textContent; } /* ========== 模块3:客栈同福监控功能 ========== */ function startFragmentMonitor() { stopFragmentMonitor(); const interval = CONFIG.fragmentMonitor.interval * 3600 * 1000; checkTargetPage(); module3Timer = setInterval(checkTargetPage, interval); Mylog("[来福监控] 已启动,间隔:" + CONFIG.fragmentMonitor.interval + "小时"); } function stopFragmentMonitor() { if (module3Timer) { clearInterval(module3Timer); module3Timer = null; Mylog("[来福监控] 已停止"); } } function checkTargetPage() { Mylog("[来福监控] 开始检查目标页面"); GM_xmlhttpRequest({ method: 'GET', url: CONFIG.fragmentMonitor.checkUrl, onload: function(response) { const text = response.responseText; const shouldJump = CONFIG.fragmentMonitor.triggerKeywords.some( keyword => text.includes(keyword+"碎片") ) && !CONFIG.fragmentMonitor.stopKeywords.some( keyword => text.includes(keyword) ); if (shouldJump) { Mylog("[来福监控] 检测到目标碎片,准备跳转"); window.location.href = CONFIG.fragmentMonitor.jumpUrl; } else { Mylog("[来福监控] 未检测到目标碎片"); } }, onerror: function(error) { console.error("[来福监控] 检查失败:", error); } }); } function saveFragmentMonitorSettings() { const interval = parseInt(document.getElementById('fragmentMonitorInterval').value); const triggerKeywords = document.getElementById('fragmentTriggerKeywords').value .split(/[,,]/) .map(s => s.trim()) .filter(s => s); const stopKeywords = document.getElementById('fragmentStopKeywords').value .split(/[,,]/) .map(s => s.trim()) .filter(s => s); CONFIG.fragmentMonitor.interval = interval; CONFIG.fragmentMonitor.triggerKeywords = triggerKeywords; CONFIG.fragmentMonitor.stopKeywords = stopKeywords; GM_setValue('fragmentMonitorInterval', interval); GM_setValue('fragmentTriggerKeywords', triggerKeywords); GM_setValue('fragmentStopKeywords', stopKeywords); if (CONFIG.fragmentMonitor.enabled) { stopFragmentMonitor(); startFragmentMonitor(); } } /* ========== 模块4:侠客岛任务模块 ========== */ let knightIslandObserver = null; const TASK_DELAY = 5000; let knightIslandCheckTimer = null; function initKnightIsland() { if (isKnightIslandPage()) { modifyKnightLinks(); knightIslandObserver = new MutationObserver(function(mutations) { const shouldUpdate = mutations.some(mutation => { return Array.from(mutation.addedNodes).some(node => { return node.nodeType === 1 && (node.querySelector('a[href*="op=refreshmission"]') || node.textContent.includes('今日免费刷新剩余')); }); }); if (shouldUpdate) { modifyKnightLinks(); } }); knightIslandObserver.observe(document.body, { childList: true, subtree: true, characterData: true }); } startAutoClaimCheck(); } function isKnightIslandPage() { return location.href.includes('cmd=knight_island'); } function modifyKnightLinks() { const refreshText = document.body.textContent.match(/今日免费刷新剩余:(\d+)次/); const freeRefreshCount = refreshText ? parseInt(refreshText[1]) : 0; const refreshLinks = document.querySelectorAll('a[href*="op=refreshmission"]'); if (freeRefreshCount === 0) { refreshLinks.forEach(link => { link.style.opacity = '0.5'; link.style.pointerEvents = 'none'; link.style.cursor = 'not-allowed'; link.title = '今日免费刷新次数已用完'; link.addEventListener('click', function(e) { e.preventDefault(); alert('今日免费刷新次数已用完!'); }); }); } else { refreshLinks.forEach(link => { link.style.opacity = ''; link.style.pointerEvents = ''; link.style.cursor = ''; link.title = ''; }); } const viewLinks = document.querySelectorAll('a[href*="op=viewmissiondetail"]'); viewLinks.forEach(link => { if (link.dataset.ledouProcessed) return; link.dataset.ledouProcessed = 'true'; const badge = document.createElement('span'); badge.textContent = '⚡'; badge.className = 'knight-badge'; link.classList.add('knight-link'); link.appendChild(badge); link.addEventListener('click', function(e) { e.preventDefault(); const url = new URL(this.href); const params = Object.fromEntries(url.searchParams.entries()); try { executeTaskFlow( params.zapp_uin, params.sid, params.pos || '0', this.href ); } catch (error) { Mylog('任务执行出错:', error); } }); }); } function executeTaskFlow(zapp_uin, sid, pos, originalUrl) { const baseUrl = `https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?zapp_uin=${zapp_uin}&sid=${sid}&channel=0&g_ut=1&cmd=knight_island&pos=${pos}`; Promise.resolve() .then(() => safeRequest(`${baseUrl}&op=viewmissiondetail`)) .then(() => safeRequest(`${baseUrl}&op=autoassign`)) .then(() => safeRequest(`${baseUrl}&op=autoassign`)) .then(() => { window.location.href = `${baseUrl}&op=begin`; }) .catch(error => { Mylog('任务执行出错:', error); window.location.href = originalUrl; }); } function startAutoClaimCheck() { stopAutoClaimCheck(); checkAndClaimRewards(); knightIslandCheckTimer = setInterval(() => { checkAndClaimRewards(); }, 5 * 60 * 1000); } function stopAutoClaimCheck() { if (knightIslandCheckTimer) { clearInterval(knightIslandCheckTimer); knightIslandCheckTimer = null; } } function checkAndClaimRewards() { if (!CONFIG.knightIsland.enabled) return; fetchKnightIslandData() .then(data => { if (data.hasRewards) { Mylog(`[侠客岛] 发现${data.rewardCount}个可领取奖励,开始远程领取`); claimRewardsRemotely(data.rewardLinks); } }); } function claimRewardsRemotely(rewardLinks) { rewardLinks.forEach((link, index) => { setTimeout(() => { const fullUrl = `https:${link.getAttribute('href')}`; GM_xmlhttpRequest({ method: "GET", url: fullUrl, onload: function(response) { Mylog(`[侠客岛] 远程领取成功: ${fullUrl}`); }, onerror: function(error) { Mylog(`[侠客岛] 远程领取失败: ${fullUrl}`, error); } }); }, index * TASK_DELAY); }); } function fetchKnightIslandData() { return new Promise((resolve) => { const missionUrl = "https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?cmd=knight_island&op=viewmissionindex"; GM_xmlhttpRequest({ method: "GET", url: missionUrl, onload: function(response) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, "text/html"); const rewardLinks = [...doc.querySelectorAll('a[href*="op=getmissionreward"]')]; resolve({ hasRewards: rewardLinks.length > 0, rewardCount: rewardLinks.length, rewardLinks: rewardLinks, missionUrl: missionUrl }); } catch (e) { console.error("[侠客岛] 解析任务数据失败:", e); resolve({ hasRewards: false }); } }, onerror: function(error) { console.error("[侠客岛] 获取任务数据失败:", error); resolve({ hasRewards: false }); } }); }); } function deinitKnightIsland() { if (knightIslandObserver) { knightIslandObserver.disconnect(); knightIslandObserver = null; } stopAutoClaimCheck(); const processedLinks = document.querySelectorAll('[data-ledou-processed]'); processedLinks.forEach(link => { delete link.dataset.ledouProcessed; const badge = link.querySelector('.knight-badge'); if (badge) badge.remove(); link.classList.remove('knight-link'); link.replaceWith(link.cloneNode(true)); }); } function saveKnightIslandSettings() { const checkInterval = parseInt(document.getElementById('knightIslandCheckInterval').value); const backgroundCheck = document.getElementById('knightIslandBackgroundCheck').checked; CONFIG.knightIsland.checkInterval = checkInterval; CONFIG.knightIsland.backgroundCheck = backgroundCheck; GM_setValue('knightIslandCheckInterval', checkInterval); GM_setValue('knightIslandBackgroundCheck', backgroundCheck); if (CONFIG.knightIsland.enabled && backgroundCheck) { startAutoClaimCheck(); } else { stopAutoClaimCheck(); } Mylog("[侠客岛] 设置已保存"); } function safeRequest(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, onload: resolve, onerror: reject }); }); } /* ========== 模块5:每日黄历 ========== */ function fetchBuffInfo() { GM_xmlhttpRequest({ method: "GET", url: "https://fight.pet.qq.com/cgi-bin/petpk?cmd=calender", onload: (response) => { try { const data = JSON.parse(response.responseText); const simplifiedBuff = simplifyBuff(data.buff); displayBuff(simplifiedBuff); } catch (e) { console.error(e); } } }); } const BUFF_MAPPING = { "斗神塔": "刷塔", "画卷": "画卷", "副本经验双倍": "副本", "乐斗经验双倍": "经验", "阅历双倍": "阅历", "暂无": "OvO" }; function simplifyBuff(buffText) { if (!buffText) return "OvO"; for (const [keyword, simplified] of Object.entries(BUFF_MAPPING)) { if (buffText.includes(keyword)) { return simplified; } } return buffText.length > 20 ? buffText.substring(0, 20) + "..." : buffText; } function displayBuff(buffText) { const title = document.getElementById('panelTitle'); if (title && !title.querySelector('.buff-info')) { const buffSpan = document.createElement('span'); buffSpan.className = 'buff-info'; buffSpan.style.marginLeft = '10px'; buffSpan.style.fontSize = '14px'; buffSpan.style.color = '#FFD700'; buffSpan.textContent = `[${buffText || "暂无"}]`; title.appendChild(buffSpan); } } /* ========== 模块6:抢地盘 ========== */ function startTerritoryGrabber() { territoryGrabberRetryCount = 0; Mylog("[抢地盘] 功能已启动,正在寻找目标地盘..."); executeTerritoryGrabber(); } function stopTerritoryGrabber() { Mylog("[抢地盘] 功能已停止"); territoryGrabberRetryCount = 0; } async function executeTerritoryGrabber() { if (!CONFIG.territoryGrabber.enabled) return; try { Mylog("[抢地盘] 正在获取地盘列表..."); const data = await getRecommendmanorData(); if (data.result === "0" && data.manors?.length > 0) { const targetManor = data.manors.find(manor => manor.ownerlevel === CONFIG.territoryGrabber.targetLevel.toString() ); if (targetManor) { await attackManor(targetManor.id); await getReward(); await getReward(); Mylog(`[抢地盘] 找到${CONFIG.territoryGrabber.targetLevel}级NPC地盘: ${targetManor.name}, ID: ${targetManor.id}`); CONFIG.territoryGrabber.enabled = false; GM_setValue('territoryGrabberEnabled', false); document.getElementById('territoryGrabberToggle').checked = false; Mylog("[抢地盘] 操作完成,功能已自动关闭"); } else { handleTerritoryRetry("未找到目标等级NPC地盘"); } } else { handleTerritoryRetry("获取地盘列表失败或列表为空"); } } catch (e) { console.error("[抢地盘] 操作失败:", e); handleTerritoryRetry(e.message); } } function handleTerritoryRetry(reason) { territoryGrabberRetryCount++; Mylog(`[抢地盘] ${reason},准备重试 (${territoryGrabberRetryCount}`); setTimeout(executeTerritoryGrabber, CONFIG.territoryGrabber.baseDelay); } function getRecommendmanorData() { return new Promise((resolve, reject) => { const apiUrl = 'https://fight.pet.qq.com/cgi-bin/petpk?cmd=recommendmanor&type=11&page=1'; GM_xmlhttpRequest({ method: "GET", url: apiUrl, timeout: 10000, onload: function(response) { try { if (!response.responseText || response.responseText.trim().startsWith('<')) { throw new Error('服务器返回无效响应'); } const data = JSON.parse(response.responseText); if (data.result !== "0") { throw new Error(data.msg || '服务器返回错误'); } if (!data.manors || !Array.isArray(data.manors)) { throw new Error('无效的地盘数据'); } resolve(data); } catch (e) { console.error('[抢地盘] 解析失败:', e); reject(e); } }, onerror: function(error) { reject(new Error(`请求失败: ${error.statusText}`)); }, ontimeout: function() { reject(new Error('请求超时')); } }); }); } function attackManor(manorId) { return new Promise((resolve, reject) => { const attackUrl = `https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?cmd=manorfight&fighttype=1&manorid=${manorId}`; Mylog(`[抢地盘] 正在抢夺地盘: ${manorId}`); GM_xmlhttpRequest({ method: "GET", url: attackUrl, onload: function(response) { try { const result = JSON.parse(response.responseText); if (result.result === "0") { Mylog("[抢地盘] 抢夺成功"); } else { Mylog("[抢地盘] 抢夺失败", result.msg || "未知错误"); } } catch (e) { console.error("[抢地盘] 抢夺结果失败:", e); } finally { resolve(); } }, onerror: function(error) { console.error("[抢地盘] 抢夺请求失败:", error); resolve(); } }); }); } function getReward() { return new Promise((resolve) => { const rewardUrl = "https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?cmd=manorget&type=1"; Mylog("[抢地盘] 正在尝试领取奖励..."); GM_xmlhttpRequest({ method: "GET", url: rewardUrl, onload: function(response) { try { const result = JSON.parse(response.responseText); if (result.result === "0") { Mylog("[抢地盘] 奖励领取成功"); } else { Mylog("[抢地盘] 奖励领取失败:", result.msg || "未知错误"); } } catch (e) { console.error("[抢地盘] 解析奖励结果失败:", e); } finally { resolve(); } }, onerror: function(error) { console.error("[抢地盘] 领取奖励请求失败:", error); resolve(); } }); }); } function saveTerritoryGrabberSettings() { const targetLevel = parseInt(document.getElementById('territoryGrabberTargetLevel').value); const retryLimit = parseInt(document.getElementById('territoryGrabberRetryLimit').value); const baseDelay = parseInt(document.getElementById('territoryGrabberBaseDelay').value); const maxRandomDelay = parseInt(document.getElementById('territoryGrabberMaxRandomDelay').value); CONFIG.territoryGrabber.targetLevel = targetLevel; CONFIG.territoryGrabber.retryLimit = retryLimit; CONFIG.territoryGrabber.baseDelay = baseDelay; CONFIG.territoryGrabber.maxRandomDelay = maxRandomDelay; GM_setValue('territoryGrabberTargetLevel', targetLevel); GM_setValue('territoryGrabberRetryLimit', retryLimit); GM_setValue('territoryGrabberBaseDelay', baseDelay); GM_setValue('territoryGrabberMaxRandomDelay', maxRandomDelay); Mylog("[抢地盘] 设置已保存"); } /* ========== 模块7:商品库存显示 ========== */ function isViewGoodsPage() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('cmd') === 'viewgoods'; } function getGoodsId() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('id'); } function getGoodsStock(goodsId, callback) { const apiUrl = `https://dld.qzapp.z.qq.com/qpet/cgi-bin/phonepk?zapp_uin=&sid=&channel=0&g_ut=1&cmd=owngoods&id=${goodsId}`; GM_xmlhttpRequest({ method: "GET", url: apiUrl, onload: function(response) { if (response.status === 200) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, "text/html"); const content = doc.body.textContent || ""; if (content.includes("繁忙")) { callback(0, "API繁忙"); } else { const match = content.match(/数量:\s*(\d+)/); if (match && match[1]) { callback(parseInt(match[1]), null); } else { callback(0, "无法解析数量"); } } } catch (e) { callback(0, "解析响应失败"); } } else { callback(0, `请求失败: ${response.status}`); } }, onerror: function(error) { callback(0, "网络请求错误"); }, timeout: 10000 }); } function displayStockInfo(goodsId, stock, error) { const firstParagraph = document.querySelector('body > div > p:first-child'); if (firstParagraph) { const textNodes = []; const walker = document.createTreeWalker(firstParagraph, NodeFilter.SHOW_TEXT, null, false); let node; while (node = walker.nextNode()) { textNodes.push(node); } if (textNodes.length > 0) { const goodsNameNode = textNodes[0]; const existingStock = document.getElementById('goods-stock-info'); if (existingStock) { existingStock.remove(); } const stockInfo = document.createElement('span'); stockInfo.id = 'goods-stock-info'; stockInfo.style.marginLeft = '5px'; stockInfo.style.fontSize = 'inherit'; stockInfo.style.fontFamily = 'inherit'; stockInfo.style.color = stock > 0 ? '#00aa00' : '#ff0000'; if (error) { stockInfo.textContent = `【背包数量:0】`; stockInfo.title = error; } else { stockInfo.textContent = `【背包数量:${stock}】`; } goodsNameNode.parentNode.insertBefore(stockInfo, goodsNameNode.nextSibling); } } } function checkAndDisplayGoodsStock() { if (!CONFIG.goodsStock.enabled) return; const goodsId = getGoodsId(); if (!goodsId) { console.log('未找到商品ID'); return; } getGoodsStock(goodsId, function(stock, error) { displayStockInfo(goodsId, stock, error); }); } function makePanelDraggable(panel) { const title = panel.querySelector('h3'); let isDragging = false; let offsetX, offsetY; title.addEventListener('mousedown', function(e) { isDragging = true; offsetX = e.clientX - panel.getBoundingClientRect().left; offsetY = e.clientY - panel.getBoundingClientRect().top; panel.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; panel.style.left = (e.clientX - offsetX) + 'px'; panel.style.top = (e.clientY - offsetY) + 'px'; panel.style.right = 'auto'; panel.style.bottom = 'auto'; }); document.addEventListener('mouseup', function() { isDragging = false; panel.style.cursor = ''; }); } function Mylog(message) { const now = new Date(); const timeStr = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; console.log(`[${timeStr}] ${message}`); } // 创建控制面板UI function createControlPanel() { // 准备替换规则的显示文本(暂未使用) // 获取武器关键词默认显示 const weaponKeywordsStr = (CONFIG.textGame.weaponHighlightKeywords || []).join(','); GM_addStyle(` #gameHelperPanel { position: fixed; bottom: 50px; right: 30px; width: 200px; max-height: 90vh; overflow-y: auto; background: rgba(0, 0, 0, 0.9); color: white; border-radius: 5px; padding: 8px; z-index: 9999; font-family: Arial, sans-serif; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); } #gameHelperPanel h3 { margin-top: 0; padding-bottom: 5px; border-bottom: 1px solid #444; cursor: move; } .module { margin-bottom: 10px; padding: 8px; background: rgba(255, 255, 255, 0.1); border-radius: 3px; } .module-title { font-weight: bold; margin-bottom: 3px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; font-size: 14px; } .module-content { padding-left: 10px; display: none; } .module.active .module-content { display: block; } .switch { position: relative; display: inline-block; width: 36px; height: 18px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 18px; } .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 2px; bottom: 2px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background-color: #2196F3; } input:checked + .slider:before { transform: translateX(16px); } .settings { font-size: 12px; margin-top: 5px; } .settings label { display: block; margin: 5px 0; } .settings input[type="text"], .settings input[type="number"], .settings textarea { width: 100%; padding: 3px; box-sizing: border-box; background: rgba(255, 255, 255, 0.2); border: 1px solid #444; color: white; font-family: monospace; font-size: 11px; } .settings textarea { resize: vertical; min-height: 60px; } .settings button { background: #2196F3; color: white; border: none; padding: 3px 8px; border-radius: 3px; cursor: pointer; margin-top: 5px; } .settings button:hover { background: #0b7dda; } .knight-link { position: relative; } .knight-badge { position: absolute; top: -5px; right: -5px; font-size: 10px; color: gold; } .task-auto-info { color: #888; font-size: 12px; margin-top: 5px; } .scheduled-task-item { background: rgba(255,255,255,0.05); border: 1px solid #444; border-radius: 3px; margin-bottom: 8px; padding: 6px; } .task-header { display: flex; align-items: center; gap: 5px; margin-bottom: 5px; } .task-header .task-name { flex: 1; background: rgba(255,255,255,0.1); border: 1px solid #555; color: white; padding: 2px 4px; font-size: 12px; min-width: 60px; } .task-remove { background: #ff4444; color: white; border: none; width: 16px; height: 16px; border-radius: 50%; cursor: pointer; font-size: 11px; font-weight: bold; display: flex; align-items: center; justify-content: center; padding: 0; flex-shrink: 0; } .task-remove:hover { background: #ff0000; transform: scale(1.1); } .task-body { padding-left: 24px; } .task-body label { display: block; margin-bottom: 3px; font-size: 10px; color: #ccc; } .task-body input[type="text"], .task-body input[type="time"], .task-body input[type="number"] { width: 100%; padding: 2px 4px; box-sizing: border-box; background: rgba(255,255,255,0.2); border: 1px solid #555; color: white; font-size: 11px; margin-top: 1px; } .task-body input[type="number"]::-webkit-inner-spin-button, .task-body input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } .task-body input[type="number"] { -moz-appearance: textfield; } .task-settings-row { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-top: 5px; } .task-settings-row label { font-size: 9px; } .task-settings-row input { width: 100% !important; margin-top: 1px; font-size: 10px; } .task-controls { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin-top: 6px; } .task-controls button { background: #2196F3; color: white; border: none; padding: 3px 4px; border-radius: 2px; cursor: pointer; font-size: 10px; text-align: center; white-space: nowrap; } .task-controls button:hover { background: #0b7dda; } .task-controls #testScheduledTask { background: #4CAF50; grid-column: span 2; } #scheduledTasksList { max-height: 180px; overflow-y: auto; margin-bottom: 6px; padding-right: 2px; } #scheduledTasksList::-webkit-scrollbar { width: 4px; } #scheduledTasksList::-webkit-scrollbar-track { background: rgba(255,255,255,0.1); border-radius: 2px; } #scheduledTasksList::-webkit-scrollbar-thumb { background: #555; border-radius: 2px; } #scheduledTasksList::-webkit-scrollbar-thumb:hover { background: #666; } #taskCountBadge { background: rgba(76, 175, 80, 0.2); padding: 0 3px; border-radius: 2px; margin-left: 4px; font-size: 10px; } #taskStatus { font-size: 9px; color: #888; margin-top: 4px; text-align: center; } .keyword-hint { font-size: 9px; color: #aaa; margin-top: 2px; margin-bottom: 5px; font-style: italic; } .separator { border-top: 1px solid #444; margin: 8px 0; } `); const panel = document.createElement('div'); panel.id = 'gameHelperPanel'; panel.innerHTML = `

请你愉快

繁忙乐斗
定时刷新
小二上酒
侠客行
自动领取并执行剩余任务
抢个地盘
文字游戏
💡 提示:输入你想高亮的关键字或武器名,用逗号分隔
定时任务 (${CONFIG.scheduledTasks.tasks.length})
每天自动执行HTTP请求
当前有 ${CONFIG.scheduledTasks.tasks.length} 个任务
`; document.body.appendChild(panel); fetchBuffInfo(); document.querySelectorAll('.module-title').forEach(title => { title.addEventListener('click', function() { this.parentElement.classList.toggle('active'); }); }); document.getElementById('systemBusyToggle').addEventListener('change', function() { CONFIG.systemBusy.enabled = this.checked; GM_setValue('systemBusyEnabled', this.checked); if (this.checked) startSystemBusyMonitor(); else stopSystemBusyMonitor(); }); document.getElementById('autoRefreshToggle').addEventListener('change', function() { CONFIG.autoRefresh.enabled = this.checked; GM_setValue('autoRefreshEnabled', this.checked); if (this.checked) startAutoRefresh(); else stopAutoRefresh(); }); document.getElementById('fragmentMonitorToggle').addEventListener('change', function() { CONFIG.fragmentMonitor.enabled = this.checked; GM_setValue('fragmentMonitorEnabled', this.checked); if (this.checked) startFragmentMonitor(); else stopFragmentMonitor(); }); document.getElementById('knightIslandToggle').addEventListener('change', function() { CONFIG.knightIsland.enabled = this.checked; GM_setValue('knightIslandEnabled', this.checked); if (this.checked) initKnightIsland(); else deinitKnightIsland(); }); document.getElementById('territoryGrabberToggle').addEventListener('change', function() { CONFIG.territoryGrabber.enabled = this.checked; GM_setValue('territoryGrabberEnabled', this.checked); if (this.checked) startTerritoryGrabber(); else stopTerritoryGrabber(); }); document.getElementById('textGameToggle').addEventListener('change', function() { CONFIG.textGame.enabled = this.checked; GM_setValue('textGameEnabled', this.checked); if (this.checked) { applyTextGame(); } else { location.reload(); } }); document.getElementById('scheduledTasksToggle').addEventListener('change', function() { CONFIG.scheduledTasks.enabled = this.checked; GM_setValue('scheduledTasksEnabled', this.checked); if (this.checked) { Mylog('[定时任务] 功能已启用'); initScheduledTasks(); } else { Mylog('[定时任务] 功能已禁用'); stopAllScheduledTasks(); } }); document.getElementById('saveSystemBusySettings').addEventListener('click', saveSystemBusySettings); document.getElementById('saveAutoRefresh').addEventListener('click', saveAutoRefreshSettings); document.getElementById('saveFragmentMonitor').addEventListener('click', saveFragmentMonitorSettings); document.getElementById('saveKnightIsland').addEventListener('click', saveKnightIslandSettings); document.getElementById('saveTerritoryGrabber').addEventListener('click', saveTerritoryGrabberSettings); document.getElementById('saveTextGameSettings').addEventListener('click', saveTextGameSettings); document.getElementById('addNewTask').addEventListener('click', addNewTask); document.getElementById('saveScheduledTasks').addEventListener('click', saveScheduledTaskSettings); document.getElementById('testScheduledTask').addEventListener('click', testFirstTask); makePanelDraggable(panel); setTimeout(() => { loadScheduledTasksUI(); updateTaskCount(); }, 100); } createControlPanel(); if (CONFIG.systemBusy.enabled) startSystemBusyMonitor(); if (CONFIG.autoRefresh.enabled) startAutoRefresh(); if (CONFIG.fragmentMonitor.enabled) startFragmentMonitor(); if (CONFIG.knightIsland.enabled) initKnightIsland(); if (CONFIG.territoryGrabber.enabled) startTerritoryGrabber(); if (CONFIG.textGame.enabled) applyTextGame(); if (CONFIG.goodsStock.enabled && isViewGoodsPage()) checkAndDisplayGoodsStock(); if (CONFIG.directionKey.enabled) initDirectionKeyControl(); if (CONFIG.scheduledTasks.enabled) { setTimeout(() => { Mylog('[定时任务] 启动定时任务监控'); initScheduledTasks(); setupDailyCheck(); setInterval(checkTaskStatus, 60 * 60 * 1000); checkTaskStatus(); }, 3000); } document.addEventListener('visibilitychange', () => { if (!document.hidden && CONFIG.scheduledTasks.enabled) { Mylog('[定时任务] 页面重新激活,检查定时任务状态...'); CONFIG.scheduledTasks.tasks.forEach(task => { if (task.enabled && task.timerId) { Mylog(`[定时任务 ${task.name}] 页面激活时检查定时器状态`); } else if (task.enabled && !task.timerId) { Mylog(`[定时任务 ${task.name}] 定时器丢失,重新设置`); setupScheduledTaskTimer(task); } }); setTimeout(() => { if (CONFIG.scheduledTasks.enabled) { initScheduledTasks(); } }, 5000); } }); window.taskManager = { executeTask: function(taskName) { Mylog(`[定时任务API] 手动执行任务: ${taskName}`); return executeTaskNow(taskName); }, getTasks: function() { Mylog('[定时任务API] 获取所有任务列表'); return CONFIG.scheduledTasks.tasks.map(task => ({ name: task.name, url: task.url, time: task.time, count: task.count, interval: task.interval / 1000, enabled: task.enabled })); }, addTask: function(task) { Mylog(`[定时任务API] 添加新任务: ${task.name || '未命名任务'}`); CONFIG.scheduledTasks.tasks.push({ name: task.name || '新任务', url: task.url, time: task.time || '00:00:01', count: task.count || 3, interval: (task.interval || 1) * 1000, enabled: true }); GM_setValue('scheduledTasks', CONFIG.scheduledTasks.tasks); if (CONFIG.scheduledTasks.enabled) { initScheduledTasks(); } return true; }, removeTask: function(taskName) { Mylog(`[定时任务API] 移除任务: ${taskName}`); const index = CONFIG.scheduledTasks.tasks.findIndex(t => t.name === taskName); if (index !== -1) { CONFIG.scheduledTasks.tasks.splice(index, 1); GM_setValue('scheduledTasks', CONFIG.scheduledTasks.tasks); if (CONFIG.scheduledTasks.enabled) { initScheduledTasks(); } return true; } return false; }, resetTimers: function() { Mylog('[定时任务API] 重置所有定时器'); initScheduledTasks(); } }; })();