Last active
January 28, 2026 07:20
-
-
Save Ansen/04af8cc1465388cc56b5597228e37cd0 to your computer and use it in GitHub Desktop.
文字传奇界面调整(优化版)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name 文字传奇界面调整(优化版) | |
| // @version 2026-01-27 | |
| // @description 调整界面文字传奇布局(更稳健、更易维护) | |
| // @author reginfos,langge | |
| // @match https://chuanqi.makifx.com/ | |
| // @grant GM_addStyle | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| /******************** | |
| * 样式统一管理 | |
| ********************/ | |
| GM_addStyle(` | |
| #stats-inventory { | |
| max-height: 200px !important; | |
| overflow-y: auto !important; | |
| overflow-x: hidden !important; | |
| } | |
| .hidden { | |
| display: none !important; | |
| } | |
| .status-card, .side { | |
| height: 600px; /* 你自己调 */ | |
| max-height: 600px; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| } | |
| `); | |
| /******************** | |
| * 工具函数 | |
| ********************/ | |
| const $ = (sel) => document.querySelector(sel); | |
| const $$ = (sel) => Array.from(document.querySelectorAll(sel)); | |
| function safeAppend(parent, child) { | |
| if (parent && child) { | |
| parent.appendChild(child); | |
| } | |
| } | |
| function safeRemove(el) { | |
| if (el) { | |
| el.remove(); | |
| } | |
| } | |
| function swapDivs(parentSelector, index1, index2) { | |
| const parent = $(parentSelector); | |
| if (!parent) return; | |
| const children = Array.from(parent.children); | |
| if ( | |
| index1 < 0 || index2 < 0 || | |
| index1 >= children.length || | |
| index2 >= children.length || | |
| index1 === index2 | |
| ) return; | |
| const el1 = children[index1]; | |
| const el2 = children[index2]; | |
| const next = el2.nextSibling === el1 ? el2 : el2.nextSibling; | |
| parent.insertBefore(el1, el2); | |
| parent.insertBefore(el2, next); | |
| } | |
| /******************** | |
| * 主逻辑(等待 DOM 就绪) | |
| ********************/ | |
| function init() { | |
| const statusCards = $$('.status-card'); | |
| const actionGroups = $$('.action-group'); | |
| const sideActionGroups = $$('.side .action-group'); | |
| // 将目标放到【行动面板】 | |
| //safeAppend(statusCards[1], actionGroups[3]); | |
| // 将技能框放到【常用操作】 | |
| safeAppend(statusCards[2],sideActionGroups[1]); | |
| // 将召唤框放到【属性框】 | |
| safeAppend(statusCards[0],sideActionGroups[3]); | |
| // 将物品放到【属性框】 | |
| safeAppend(statusCards[1], actionGroups[4]); | |
| // 将移动面板移动到上面 | |
| const statusGrid = $('.status-grid'); | |
| const sidePanel = $('.side'); | |
| safeAppend(statusGrid, sidePanel); | |
| // 去掉头部文字 | |
| safeRemove($('header')); | |
| // 页面整体样式调整 | |
| const app = $('#app'); | |
| if (app) { | |
| app.style.padding = '0'; | |
| app.style.maxWidth = 'none'; | |
| } | |
| // 上方人物信息:4 列 | |
| if (statusGrid) { | |
| statusGrid.style.setProperty( | |
| 'grid-template-columns', | |
| 'repeat(4, minmax(0, 1fr))' | |
| ); | |
| } | |
| // 聊天区域调整 | |
| const gameGrid = $('.game-grid'); | |
| if (gameGrid) { | |
| gameGrid.style.setProperty('grid-template-columns', '2fr 2fr'); | |
| } | |
| // 怪物目标框高度 | |
| if (actionGroups[3]) { | |
| actionGroups[3].style.height = '150px'; | |
| } | |
| // 隐藏修炼框 | |
| if (actionGroups[7]) { | |
| actionGroups[7].classList.add('hidden'); | |
| } | |
| // 系统日志移动到和聊天框平级 | |
| const logWrap = $('.log-wrap'); | |
| safeAppend(gameGrid, logWrap); | |
| // 交换聊天框和系统日志位置 | |
| swapDivs('.game-grid', 0, 1); | |
| // 日志高度调整 | |
| const log = $('#log'); | |
| if (log) { | |
| log.style.minHeight = 'auto'; | |
| log.style.height = '320px'; | |
| } | |
| } | |
| /******************** | |
| * DOM Ready | |
| ********************/ | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', init); | |
| } else { | |
| init(); | |
| } | |
| })(); |
Author
Author
// ==UserScript==
// @name 文字传奇智能挂机控制
// @version 2026-01-27
// @description 监控蓝量,自动停止/恢复挂机,智能选择挂机技能
// @author reginfos
// @match https://chuanqi.makifx.com/
// @grant GM_addStyle
// @grant GM_notification
// ==/UserScript==
(function () {
'use strict';
// 配置
const CONFIG = {
stopManaThreshold: 20, // 蓝量低于20%时停止挂机
resumeManaThreshold: 100, // 蓝量恢复到100%时恢复挂机
checkInterval: 3000, // 每3秒检查一次
enableNotification: true, // 启用浏览器通知
debug: true, // 显示调试信息
// 挂机设置
autoSelectBestSkills: true, // 自动选择"自动最强"
skillSelectDelay: 800, // 技能选择延迟(毫秒)
maxRetryCount: 3 // 最大重试次数
};
// 添加样式
GM_addStyle(`
.smart-hangup-control {
position: fixed;
top: 10px;
right: 10px;
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 12px 15px;
border-radius: 10px;
font-size: 12px;
z-index: 99999;
border: 2px solid #4CAF50;
font-family: 'Microsoft YaHei', Arial, sans-serif;
min-width: 220px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
backdrop-filter: blur(10px);
user-select: none;
}
.smart-hangup-control.waiting {
border-color: #ff9800;
background: rgba(255, 152, 0, 0.15);
}
.smart-hangup-control.stopped {
border-color: #f44336;
background: rgba(244, 67, 54, 0.15);
}
.smart-hangup-control.selecting {
border-color: #9C27B0;
background: rgba(156, 39, 176, 0.15);
animation: selecting-pulse 1.5s infinite;
}
@keyframes selecting-pulse {
0% { box-shadow: 0 0 0 0 rgba(156, 39, 176, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(156, 39, 176, 0); }
100% { box-shadow: 0 0 0 0 rgba(156, 39, 176, 0); }
}
.control-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #444;
}
.control-title {
font-weight: bold;
font-size: 14px;
display: flex;
align-items: center;
gap: 5px;
}
.title-icon {
font-size: 16px;
}
.control-status {
font-size: 10px;
padding: 3px 8px;
border-radius: 12px;
background: #4CAF50;
color: white;
font-weight: bold;
}
.control-status.waiting {
background: #ff9800;
}
.control-status.stopped {
background: #f44336;
}
.control-status.selecting {
background: #9C27B0;
}
.mana-display {
margin: 8px 0;
}
.mana-text {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.current-mana {
font-weight: bold;
color: #4FC3F7;
}
.mana-threshold {
font-size: 10px;
color: #aaa;
}
.mana-bar-container {
height: 10px;
background: #2C2C2C;
border-radius: 5px;
overflow: hidden;
position: relative;
}
.mana-bar-fill {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #2196F3, #03A9F4);
border-radius: 5px;
transition: width 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
position: relative;
}
.mana-bar-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent);
animation: shimmer 2s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.mana-bar-fill.low {
background: linear-gradient(90deg, #ff9800, #ffb74d);
}
.mana-bar-fill.critical {
background: linear-gradient(90deg, #f44336, #ff7961);
}
.mana-bar-fill.full {
background: linear-gradient(90deg, #4CAF50, #8BC34A);
}
.control-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
margin: 10px 0;
}
.ctrl-btn {
padding: 6px 10px;
border: none;
border-radius: 6px;
background: #444;
color: white;
cursor: pointer;
font-size: 11px;
font-weight: bold;
transition: all 0.2s;
text-align: center;
}
.ctrl-btn:hover {
transform: translateY(-1px);
box-shadow: 0 3px 8px rgba(0,0,0,0.3);
}
.ctrl-btn:active {
transform: translateY(0);
}
.ctrl-btn.primary {
background: linear-gradient(135deg, #4CAF50, #45a049);
}
.ctrl-btn.danger {
background: linear-gradient(135deg, #f44336, #d32f2f);
}
.ctrl-btn.warning {
background: linear-gradient(135deg, #ff9800, #f57c00);
}
.ctrl-btn.purple {
background: linear-gradient(135deg, #9C27B0, #7B1FA2);
}
.stats-panel {
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
padding: 8px;
margin-top: 8px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 5px;
font-size: 10px;
}
.stat-item {
text-align: center;
}
.stat-label {
color: #aaa;
margin-bottom: 2px;
}
.stat-value {
color: white;
font-weight: bold;
font-size: 11px;
}
.last-action {
margin-top: 5px;
padding-top: 5px;
border-top: 1px solid #333;
font-size: 9px;
color: #888;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 按钮数据属性 */
[data-hangup-action] {
cursor: pointer;
}
/* 调试信息样式 */
.hangup-debug-info {
position: fixed;
top: 50px;
right: 10px;
background: rgba(0, 0, 0, 0.8);
color: #0f0;
padding: 8px;
border-radius: 4px;
font-size: 11px;
font-family: monospace;
z-index: 99998;
max-width: 300px;
max-height: 200px;
overflow: auto;
display: none;
}
`);
// 工具函数
const $ = (sel) => document.querySelector(sel);
const $$ = (sel) => Array.from(document.querySelectorAll(sel));
// 智能挂机控制器
class SmartHangupController {
constructor() {
this.isActive = true;
this.isMonitoring = true;
this.isHangupStopped = false;
this.isSelectingSkills = false;
this.isSkillModalOpen = false;
this.statusElement = null;
this.manaBarElement = null;
this.checkTimer = null;
this.skillSelectTimer = null;
this.retryCount = 0;
this.debugInfoElement = null;
this.stats = {
totalChecks: 0,
lowManaEvents: 0,
autoStops: 0,
autoResumes: 0,
skillSelects: 0,
lastAction: '初始化',
lastActionTime: null
};
// 绑定方法
this.handleButtonClick = this.handleButtonClick.bind(this);
this.handleGlobalKeydown = this.handleGlobalKeydown.bind(this);
this.init();
}
init() {
this.createControlPanel();
this.createDebugInfo();
this.setupEventListeners();
this.startMonitoring();
this.log('智能挂机控制已启动');
// 启动技能选择检测
this.startSkillModalDetection();
// 初始检查
setTimeout(() => this.checkMana(), 1500);
// 每隔一段时间检查一次技能选择界面
setInterval(() => this.checkForSkillModal(), 1000);
}
createControlPanel() {
const oldPanel = $('.smart-hangup-control');
if (oldPanel) oldPanel.remove();
this.statusElement = document.createElement('div');
this.statusElement.className = 'smart-hangup-control';
this.statusElement.innerHTML = `
<div class="control-header">
<div class="control-title">
<span class="title-icon">🤖</span>
<span>智能挂机</span>
</div>
<span class="control-status">监控中</span>
</div>
<div class="mana-display">
<div class="mana-text">
<span>蓝量: <span class="current-mana">--/--</span></span>
<span class="mana-threshold">≤${CONFIG.stopManaThreshold}%停</span>
</div>
<div class="mana-bar-container">
<div class="mana-bar-fill"></div>
</div>
</div>
<div class="control-buttons">
<button class="ctrl-btn warning" data-hangup-action="toggleMonitoring">暂停监控</button>
<button class="ctrl-btn purple" data-hangup-action="forceStartHangup">强制挂机</button>
<button class="ctrl-btn primary" data-hangup-action="manualResume">恢复挂机</button>
<button class="ctrl-btn danger" data-hangup-action="emergencyStop">紧急停止</button>
</div>
<div class="stats-panel">
<div class="stats-grid">
<div class="stat-item">
<div class="stat-label">检查</div>
<div class="stat-value stat-checks">0</div>
</div>
<div class="stat-item">
<div class="stat-label">低蓝</div>
<div class="stat-value stat-lowmana">0</div>
</div>
<div class="stat-item">
<div class="stat-label">恢复</div>
<div class="stat-value stat-resumes">0</div>
</div>
</div>
<div class="last-action" title="最后操作">最后操作: 初始化</div>
</div>
`;
document.body.appendChild(this.statusElement);
this.manaBarElement = this.statusElement.querySelector('.mana-bar-fill');
// 存储实例引用
window.__smartHangupCtrl = this;
}
createDebugInfo() {
this.debugInfoElement = document.createElement('div');
this.debugInfoElement.className = 'hangup-debug-info';
this.debugInfoElement.innerHTML = `
<div>调试信息:</div>
<div id="debug-state">状态: 初始化</div>
<div id="debug-modal">技能框: 未检测</div>
<div id="debug-buttons">按钮: 未找到</div>
`;
document.body.appendChild(this.debugInfoElement);
// 按F3显示/隐藏调试信息
document.addEventListener('keydown', (e) => {
if (e.key === 'F3') {
this.debugInfoElement.style.display =
this.debugInfoElement.style.display === 'none' ? 'block' : 'none';
}
});
}
updateDebugInfo(state, modal, buttons) {
if (!this.debugInfoElement) return;
const stateEl = this.debugInfoElement.querySelector('#debug-state');
const modalEl = this.debugInfoElement.querySelector('#debug-modal');
const buttonsEl = this.debugInfoElement.querySelector('#debug-buttons');
if (stateEl) stateEl.textContent = `状态: ${state}`;
if (modalEl) modalEl.textContent = `技能框: ${modal}`;
if (buttonsEl) buttonsEl.textContent = `按钮: ${buttons}`;
}
setupEventListeners() {
// 使用事件委托处理按钮点击
if (this.statusElement) {
this.statusElement.addEventListener('click', this.handleButtonClick);
}
// 全局键盘事件
document.addEventListener('keydown', this.handleGlobalKeydown);
}
handleButtonClick(event) {
const button = event.target.closest('[data-hangup-action]');
if (!button) return;
const action = button.getAttribute('data-hangup-action');
event.preventDefault();
event.stopPropagation();
this.log(`按钮点击: ${action}`);
switch (action) {
case 'toggleMonitoring':
this.toggleMonitoring();
break;
case 'forceStartHangup':
this.forceStartHangup();
break;
case 'manualResume':
this.manualResume();
break;
case 'emergencyStop':
this.emergencyStop();
break;
}
}
handleGlobalKeydown(event) {
// Alt+Shift+H 切换监控
if (event.altKey && event.shiftKey && event.key === 'H') {
event.preventDefault();
this.toggleMonitoring();
}
// Alt+Shift+S 强制开始
if (event.altKey && event.shiftKey && event.key === 'S') {
event.preventDefault();
this.forceStartHangup();
}
// Alt+Shift+E 紧急停止
if (event.altKey && event.shiftKey && event.key === 'E') {
event.preventDefault();
this.emergencyStop();
}
}
startSkillModalDetection() {
// 定期检查技能选择界面
this.skillModalCheckInterval = setInterval(() => {
this.checkForSkillModal();
}, 500);
}
checkForSkillModal() {
if (!this.isSelectingSkills) return;
// 方法1: 查找特定的模态框元素
let skillModal = null;
// 查找所有模态框
const modals = $$('.modal, .modal-dialog, .modal-content, [class*="modal"], [class*="dialog"], [class*="popup"]');
for (const modal of modals) {
const text = modal.textContent || '';
if (text.includes('挂机技能') ||
text.includes('点击技能即可自动释放') ||
text.includes('自动最强') ||
text.includes('开始挂机') ||
text.includes('取消')) {
// 检查是否可见
const style = window.getComputedStyle(modal);
if (style.display !== 'none' && style.visibility !== 'hidden') {
skillModal = modal;
break;
}
}
}
// 方法2: 查找特定ID的元素
if (!skillModal) {
const afkElements = $$('#afk-skill-list, .afk-skill-list, #afk-start, #afk-auto');
for (const el of afkElements) {
const style = window.getComputedStyle(el);
if (style.display !== 'none') {
skillModal = el.closest('.modal, .modal-dialog, [class*="modal"]') || document.body;
break;
}
}
}
if (skillModal && !this.isSkillModalOpen) {
this.log('检测到技能选择界面');
this.isSkillModalOpen = true;
this.updateDebugInfo('选择技能', '已检测到', '检查中');
this.handleSkillModal(skillModal);
} else if (!skillModal && this.isSkillModalOpen) {
this.isSkillModalOpen = false;
}
// 更新调试信息
this.updateDebugInfo(
this.isSelectingSkills ? '选择中' : '监控中',
this.isSkillModalOpen ? '已打开' : '未检测',
'等待检测'
);
}
handleSkillModal(modalElement) {
this.log('处理技能选择界面');
this.updateStatus('选择技能');
// 等待界面完全渲染
setTimeout(() => {
if (CONFIG.autoSelectBestSkills) {
this.selectBestSkills();
}
}, CONFIG.skillSelectDelay);
}
selectBestSkills() {
this.log('正在选择自动最强技能...');
// 首先尝试直接查找"自动最强"按钮
let autoBestBtn = $('#afk-auto');
// 如果没找到,查找所有按钮
if (!autoBestBtn) {
const allButtons = $$('button');
for (const btn of allButtons) {
const btnText = btn.textContent.trim();
if (btnText === '自动最强' || btnText.includes('自动最强')) {
autoBestBtn = btn;
break;
}
}
}
if (autoBestBtn) {
this.log('找到"自动最强"按钮,点击选择');
this.updateDebugInfo('选择技能', '已检测到', '找到自动最强');
// 点击"自动最强"按钮
this.simulateClick(autoBestBtn);
this.stats.skillSelects++;
// 短暂延迟后点击"开始挂机"按钮
setTimeout(() => {
this.startHangupFromModal();
}, 300);
return true;
} else {
this.log('未找到"自动最强"按钮,尝试其他方式');
this.updateDebugInfo('选择技能', '已检测到', '未找到自动最强');
// 尝试直接查找"开始挂机"按钮
this.startHangupFromModal();
return false;
}
}
startHangupFromModal() {
setTimeout(() => {
// 查找"开始挂机"按钮
let startBtn = $('#afk-start');
// 如果没找到,查找所有按钮
if (!startBtn) {
const allButtons = $$('button');
for (const btn of allButtons) {
const btnText = btn.textContent.trim();
if (btnText === '开始挂机' || btnText.includes('开始挂机')) {
startBtn = btn;
break;
}
}
}
if (startBtn) {
this.log('点击"开始挂机"按钮');
this.updateDebugInfo('选择技能', '已检测到', '找到开始挂机');
this.simulateClick(startBtn);
this.isSelectingSkills = false;
this.isSkillModalOpen = false;
this.updateStatus('监控中');
// 挂机成功启动
this.isHangupStopped = false;
this.retryCount = 0;
setTimeout(() => {
this.recordAction('智能挂机已启动');
this.notify('挂机恢复', '已选择自动最强技能并开始挂机');
this.updateDebugInfo('监控中', '已关闭', '完成');
}, 500);
} else {
this.error('未找到开始挂机按钮');
this.updateDebugInfo('选择技能', '已检测到', '未找到开始挂机');
this.retrySelectSkills();
}
}, 500);
}
startHangupDirectly() {
this.log('尝试直接开始挂机');
const success = this.findAndClickHangupButton('挂机');
if (success) {
this.isHangupStopped = false;
this.retryCount = 0;
this.isSelectingSkills = false;
this.updateStatus('监控中');
this.recordAction('直接开始挂机');
this.notify('挂机恢复', '已直接开始挂机');
} else {
this.error('未找到挂机按钮');
this.retrySelectSkills();
}
}
retrySelectSkills() {
if (this.retryCount < CONFIG.maxRetryCount) {
this.retryCount++;
this.log(`重试选择技能 (${this.retryCount}/${CONFIG.maxRetryCount})`);
setTimeout(() => {
if (this.isHangupStopped) {
this.resumeAutoHangup(100); // 重新尝试恢复挂机
}
}, 2000);
} else {
this.error('达到最大重试次数,请手动操作');
this.notify('挂机失败', '已达到最大重试次数,请手动操作');
this.isSelectingSkills = false;
this.updateStatus('监控中');
}
}
startMonitoring() {
this.stopMonitoring();
this.isMonitoring = true;
this.checkTimer = setInterval(() => this.checkMana(), CONFIG.checkInterval);
this.updateStatus('监控中');
this.recordAction('监控已启动');
}
stopMonitoring() {
if (this.checkTimer) {
clearInterval(this.checkTimer);
this.checkTimer = null;
}
this.isMonitoring = false;
this.updateStatus('已暂停');
}
toggleMonitoring() {
if (this.isMonitoring) {
this.stopMonitoring();
this.notify('监控暂停', '智能挂机控制已暂停');
} else {
this.startMonitoring();
this.notify('监控恢复', '智能挂机控制已恢复');
}
}
checkMana() {
if (!this.isMonitoring) return;
this.stats.totalChecks++;
this.updateStats();
try {
const manaInfo = this.getManaInfo();
if (!manaInfo) {
this.updateDisplay('--/--', 0);
return;
}
const { current, max, percentage } = manaInfo;
this.updateDisplay(`${current}/${max}`, percentage);
// 检查是否低于停止阈值
if (percentage <= CONFIG.stopManaThreshold && !this.isHangupStopped) {
this.stopAutoHangup(percentage);
}
// 检查是否达到恢复阈值
else if (percentage >= CONFIG.resumeManaThreshold && this.isHangupStopped && !this.isSelectingSkills) {
this.resumeAutoHangup(percentage);
}
} catch (error) {
this.error('检查蓝量时出错:', error);
}
}
getManaInfo() {
// 方法1: 查找数值显示
const mpValueElement = $('#ui-mp');
if (mpValueElement) {
const text = mpValueElement.textContent.trim();
const match = text.match(/(\d+)\s*\/\s*(\d+)/);
if (match) {
const current = parseInt(match[1]);
const max = parseInt(match[2]);
const percentage = max > 0 ? (current / max) * 100 : 0;
return { current, max, percentage };
}
}
// 方法2: 查找进度条显示
const mpBarElement = $('#bar-mp');
if (mpBarElement) {
const style = mpBarElement.style.width;
const match = style.match(/(\d+(\.\d+)?)%/);
if (match) {
const percentage = parseFloat(match[1]);
let max = 0;
const mpValue = $('#ui-mp');
if (mpValue) {
const text = mpValue.textContent.trim();
const m = text.match(/\d+\s*\/\s*(\d+)/);
if (m) max = parseInt(m[1]);
}
if (max === 0) max = 1000;
const current = Math.round((percentage / 100) * max);
return { current, max, percentage };
}
}
this.log('未找到蓝量显示元素');
return null;
}
updateDisplay(valueText, percentage) {
if (!this.statusElement) return;
const manaValueSpan = this.statusElement.querySelector('.current-mana');
if (manaValueSpan) {
manaValueSpan.textContent = valueText;
}
if (this.manaBarElement) {
this.manaBarElement.style.width = `${Math.min(percentage, 100)}%`;
// 更新颜色
this.manaBarElement.className = 'mana-bar-fill';
if (percentage >= 95) {
this.manaBarElement.classList.add('full');
} else if (percentage <= CONFIG.stopManaThreshold) {
this.manaBarElement.classList.add('critical');
} else if (percentage <= CONFIG.stopManaThreshold * 2) {
this.manaBarElement.classList.add('low');
}
}
}
updateStatus(status) {
if (!this.statusElement) return;
const statusElement = this.statusElement.querySelector('.control-status');
const titleElement = this.statusElement.querySelector('.control-title');
if (statusElement) {
statusElement.textContent = status;
statusElement.className = 'control-status';
// 移除所有状态类
this.statusElement.classList.remove('waiting', 'stopped', 'selecting');
if (status === '等待回蓝' || status === '已暂停') {
statusElement.classList.add('waiting');
this.statusElement.classList.add('waiting');
} else if (status === '挂机已停') {
statusElement.classList.add('stopped');
this.statusElement.classList.add('stopped');
} else if (status === '选择技能') {
statusElement.classList.add('selecting');
this.statusElement.classList.add('selecting');
}
}
if (titleElement) {
const icon = titleElement.querySelector('.title-icon');
if (icon) {
if (status === '挂机已停') {
icon.textContent = '⛔';
} else if (status === '选择技能') {
icon.textContent = '⚡';
} else if (status === '已暂停') {
icon.textContent = '⏸️';
} else {
icon.textContent = '🤖';
}
}
}
}
updateStats() {
if (!this.statusElement) return;
const checksSpan = this.statusElement.querySelector('.stat-checks');
const lowManaSpan = this.statusElement.querySelector('.stat-lowmana');
const resumesSpan = this.statusElement.querySelector('.stat-resumes');
const lastActionSpan = this.statusElement.querySelector('.last-action');
if (checksSpan) checksSpan.textContent = this.stats.totalChecks;
if (lowManaSpan) lowManaSpan.textContent = this.stats.lowManaEvents;
if (resumesSpan) resumesSpan.textContent = this.stats.autoResumes;
if (lastActionSpan) {
lastActionSpan.textContent = `最后: ${this.stats.lastAction}`;
lastActionSpan.title = this.stats.lastAction;
}
}
recordAction(action) {
this.stats.lastAction = action;
this.stats.lastActionTime = new Date();
this.updateStats();
}
stopAutoHangup(percentage) {
this.stats.lowManaEvents++;
this.stats.autoStops++;
this.recordAction(`蓝量${percentage.toFixed(1)}%停止挂机`);
this.log(`蓝量过低 (${percentage.toFixed(1)}%),停止自动挂机`);
this.updateStatus('挂机已停');
this.isHangupStopped = true;
this.isSelectingSkills = false;
this.isSkillModalOpen = false;
this.retryCount = 0;
// 停止挂机
this.findAndClickHangupButton('停止挂机');
if (CONFIG.enableNotification) {
this.notify('挂机已停止', `蓝量过低: ${percentage.toFixed(1)}%`);
}
}
resumeAutoHangup(percentage) {
this.stats.autoResumes++;
this.recordAction(`蓝量${percentage.toFixed(1)}%恢复挂机`);
this.log(`蓝量已恢复 (${percentage.toFixed(1)}%),准备恢复挂机`);
this.updateStatus('等待回蓝');
// 设置技能选择状态
this.isSelectingSkills = true;
this.isSkillModalOpen = false;
// 点击挂机按钮(这会触发技能选择界面)
setTimeout(() => {
if (this.findAndClickHangupButton('挂机')) {
this.log('已点击挂机按钮,等待技能选择界面');
this.updateDebugInfo('等待界面', '等待中', '已点击挂机');
// 设置超时,防止界面未弹出
setTimeout(() => {
if (this.isSelectingSkills && !this.isSkillModalOpen) {
this.log('技能选择界面未弹出,尝试直接挂机');
this.startHangupDirectly();
}
}, 5000);
}
}, 1000);
}
findAndClickHangupButton(text) {
// 首先查找.chip元素
const chips = $$('.chip');
for (const chip of chips) {
if (chip.textContent.trim() === text) {
this.simulateClick(chip);
this.log(`点击按钮: ${text}`);
return true;
}
}
// 查找其他可能的按钮
const buttons = $$('button, div[onclick], span[onclick], a[onclick]');
for (const btn of buttons) {
const btnText = btn.textContent.trim();
if (btnText === text || btnText.includes(text)) {
this.simulateClick(btn);
this.log(`点击按钮: ${btnText}`);
return true;
}
}
this.log(`未找到按钮: ${text}`);
return false;
}
simulateClick(element) {
try {
// 尝试多种点击方式
if (typeof element.click === 'function') {
element.click();
} else {
const event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
element.dispatchEvent(event);
}
return true;
} catch (e) {
this.error('点击失败:', e);
return false;
}
}
forceStartHangup() {
this.log('强制开始挂机');
this.isHangupStopped = false;
this.resumeAutoHangup(100);
this.recordAction('强制开始挂机');
this.notify('强制操作', '已强制开始挂机流程');
}
manualResume() {
if (this.isHangupStopped) {
this.log('手动恢复挂机');
this.isHangupStopped = false;
this.resumeAutoHangup(100);
this.recordAction('手动恢复挂机');
}
}
emergencyStop() {
this.log('紧急停止所有操作');
this.isMonitoring = false;
this.isHangupStopped = true;
this.isSelectingSkills = false;
this.isSkillModalOpen = false;
this.stopMonitoring();
this.findAndClickHangupButton('停止挂机');
this.updateStatus('已暂停');
this.recordAction('紧急停止');
this.notify('紧急停止', '所有自动操作已停止');
}
notify(title, message) {
if (CONFIG.enableNotification && typeof GM_notification === 'function') {
GM_notification({
title: `🤖 ${title}`,
text: message,
timeout: 4000,
highlight: true
});
}
}
log(...args) {
if (CONFIG.debug) {
console.log('[智能挂机]', ...args);
}
}
error(...args) {
console.error('[智能挂机]', ...args);
}
}
// 主函数
function main() {
// 检查是否已经存在控制器
if (window.__smartHangupCtrl) {
console.log('[智能挂机] 控制器已存在,跳过初始化');
return;
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
new SmartHangupController();
}, 3000);
});
} else {
setTimeout(() => {
new SmartHangupController();
}, 3000);
}
}
// 启动
main();
})();
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
使用方法
安装 Tampermonkey 插件,然后 点击 我安装
更新内容
20260126