Greasy Fork

来自缓存

Greasy Fork is available in English.

WarSoul AutoBattle

为战魂觉醒游戏组队添加自动战斗功能,等待队员加入后自动开始战斗

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name          WarSoul AutoBattle
// @namespace     https://aring.cc/
// @version       1.0.2
// @description   为战魂觉醒游戏组队添加自动战斗功能,等待队员加入后自动开始战斗
// @author        Lunaris
// @match         https://aring.cc/awakening-of-war-soul-ol/*
// @match         https://aring.cc/awakening-of-war-soul-ol
// @icon          https://aring.cc/awakening-of-war-soul-ol/favicon.ico
// @grant         none
// @run-at        document-end
// @license       MIT
// ==/UserScript==

(function() {
    'use strict';
    console.log('[战魂觉醒自动战斗] 脚本开始加载...');

    // 辅助函数:实现 :contains 伪类功能
    function querySelector(selector, context = document) {
        if (selector.includes(':contains(')) {
            const match = selector.match(/^(.+):contains\("([^"]+)"\)$/);
            if (match) {
                const baseSelector = match[1];
                const searchText = match[2];
                const elements = context.querySelectorAll(baseSelector);
                for (let element of elements) {
                    // 检查元素自身或其子元素的文本是否包含搜索文本
                    if (element.textContent.includes(searchText)) {
                        return element;
                    }
                }
            }
            return null;
        }
        return context.querySelector(selector);
    }

    class AutoBattleHelper {
        constructor() {
            this.isAutoEnabled = false;
            this.checkInterval = null;
            this.injectedButton = null;
            this.lastRoomNumber = '';
            this.lastTeamMember = '';
            this.roomElement = null;
            this.battleStarted = false;
            this.init();
        }

        init() {
            this.waitForPageLoad();
        }

        waitForPageLoad() {
            const startInjection = () => {
                this.waitForRoomElement();
            };
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', startInjection);
            } else {
                startInjection();
            }
        }

        waitForRoomElement() {
            let attempts = 0;
            const maxAttempts = 30;

            const checkForRoom = () => {
                attempts++;
                // 不依赖 data-v 属性,使用更通用的选择器
                const roomElement = document.querySelector('.in-room.border-wrap');

                if (roomElement) {
                    this.roomElement = roomElement;
                    console.log('[战魂觉醒自动战斗] 找到房间元素,开始注入按钮');
                    this.injectAutoButton(roomElement);
                    this.startMonitoring();
                } else if (attempts < maxAttempts) {
                    setTimeout(checkForRoom, 1000);
                } else {
                    console.log('[战魂觉醒自动战斗] 未找到房间元素,停止尝试');
                }
            };
            checkForRoom();
        }

        // 简化 findRoomElement,直接使用最精确的结构
        findRoomElement() {
            // 房主和队员昵称、开始战斗按钮都在这个容器内
            return document.querySelector('.in-room.border-wrap');
        }

        injectAutoButton(roomElement) {
            if (this.injectedButton) {
                return;
            }

            // 找到包含"房间号"的 p 元素作为插入位置
            const roomInfoElements = roomElement.querySelectorAll('p.room-info');
            let targetElement = null;

            for(let p of roomInfoElements) {
                // 找到包含"房间号"的第一个 p 元素
                if(p.textContent.includes('房间号')) {
                    targetElement = p;
                    break;
                }
            }

            if (!targetElement) {
                console.log('[战魂觉醒自动战斗] 未找到房间信息元素作为插入点');
                return;
            }

            // 获取房间元素的 data-v 属性(动态适配)
            const dataVAttr = Array.from(roomElement.attributes)
                .find(attr => attr.name.startsWith('data-v-'))?.name || '';

            const autoContainer = document.createElement('p');
            if (dataVAttr) {
                autoContainer.setAttribute(dataVAttr, '');
            }
            autoContainer.className = 'room-info auto-battle-container';
            autoContainer.style.cssText = `
                margin-top: 10px;
                display: flex;
                justify-content: flex-start;
                align-items: center;
            `;

            autoContainer.innerHTML = `
                <span ${dataVAttr ? dataVAttr + '=""' : ''} style="margin-right: 10px;">等待队员加入后自动开始战斗:</span>
                <div ${dataVAttr ? dataVAttr + '=""' : ''} class="el-switch el-switch--small" style="cursor: pointer;">
                    <input class="el-switch__input" type="checkbox" role="switch"
                               aria-checked="false" aria-disabled="false"
                               style="display: none;">
                    <span class="el-switch__core" style="border-color: #dcdfe6; background-color: #dcdfe6;">
                        <div class="el-switch__action" style="background-color: #fff;"></div>
                    </span>
                </div>
            `;

            targetElement.parentNode.insertBefore(autoContainer, targetElement.nextSibling);

            const switchElement = autoContainer.querySelector('.el-switch');
            const inputElement = autoContainer.querySelector('.el-switch__input');
            const coreElement = autoContainer.querySelector('.el-switch__core');
            this.bindSwitchEvents(switchElement, inputElement, coreElement);
            this.injectedButton = autoContainer;
            console.log('[战魂觉醒自动战斗] 自动战斗按钮已成功注入');
        }

        bindSwitchEvents(switchElement, inputElement, coreElement, textElement) {
            if (!switchElement || !inputElement || !coreElement) {
                console.error('[战魂觉醒自动战斗] 开关元素绑定失败');
                return;
            }

            const toggleSwitch = (event) => {
                event.preventDefault();
                event.stopPropagation();
                this.isAutoEnabled = !this.isAutoEnabled;
                inputElement.checked = this.isAutoEnabled;
                inputElement.setAttribute('aria-checked', this.isAutoEnabled.toString());
                if (this.isAutoEnabled) {
                    switchElement.classList.add('is-checked');
                    coreElement.style.borderColor = '#409DFE';
                    coreElement.style.backgroundColor = '#409DFE';
                    if (textElement) textElement.style.color = '#409DFE';
                    console.log('[战魂觉醒自动战斗] ✅ 自动战斗已启用 - 持续监控房间状态');
                } else {
                    switchElement.classList.remove('is-checked');
                    coreElement.style.borderColor = '#dcdfe6';
                    coreElement.style.backgroundColor = '#dcdfe6';
                    if (textElement) textElement.style.color = '#909399';
                    console.log('[战魂觉醒自动战斗] ❌ 自动战斗已禁用');
                }
            };
            switchElement.addEventListener('click', toggleSwitch);
        }

        startMonitoring() {
            console.log('[战魂觉醒自动战斗] 🔍 开始监控房间和队员状态...');
            // 减少监控频率,减轻资源消耗
            this.checkInterval = setInterval(() => {
                this.checkRoomAndTeamStatus();
            }, 1500); // 调整为 1.5 秒
        }

        checkRoomAndTeamStatus() {
            if (!this.isAutoEnabled) return;

            // 始终获取最新的房间元素,以应对 DOM 变化
            const roomElement = this.roomElement || this.findRoomElement();
            if (!roomElement) {
                // 如果房间元素消失,清除计时器,等待重新初始化
                if (this.checkInterval) {
                     clearInterval(this.checkInterval);
                     this.checkInterval = null;
                     console.log('[战魂觉醒自动战斗] 房间元素丢失,停止监控。');
                }
                return;
            }
            this.roomElement = roomElement; // 确保 roomElement 始终是最新的

            const currentRoomNumber = this.getCurrentRoomNumber(roomElement);
            const currentTeamMember = this.getCurrentTeamMember(roomElement);

            // 监控房间号变化
            if (currentRoomNumber !== this.lastRoomNumber) {
                this.lastRoomNumber = currentRoomNumber;
                // 房间状态变化时重置战斗标志,以准备下一轮自动战斗
                this.battleStarted = false;
                console.log(`[战魂觉醒自动战斗] 🏠 房间号变化/重置: ${currentRoomNumber || '无房间'}`);
            }

            // 只有在有效房间内且战斗未开始,才检测队员并触发战斗
            if (this.isValidRoom(currentRoomNumber) && !this.battleStarted) {

                // 仅当检测到队员加入时才触发
                if (currentTeamMember && currentTeamMember !== this.lastTeamMember) {
                    this.lastTeamMember = currentTeamMember; // 更新队员信息

                    console.log(`[战魂觉醒自动战斗] 👥 检测到队员加入: ${currentTeamMember}`);

                    // 延迟 1.5 秒后尝试开始战斗
                    setTimeout(() => {
                        // 再次确认房间和队员状态是否仍然有效
                        if (this.isValidRoom(this.lastRoomNumber) && this.lastTeamMember === currentTeamMember && !this.battleStarted) {
                            this.autoStartBattle(currentTeamMember, currentRoomNumber);
                        }
                    }, 1500);
                } else if (!currentTeamMember) {
                    this.lastTeamMember = ''; // 队员离开
                }
            }
        }

        getCurrentRoomNumber(roomElement) {
            // 找到包含 "房间号:" 的元素
            const allSpans = roomElement.querySelectorAll('span');
            for (let span of allSpans) {
                const text = span.textContent;
                if (text.includes('房间号:') && text.match(/\d+/)) {
                    // 提取房间号数字
                    const match = text.match(/房间号:(\d+)/);
                    return match ? match[1] : '';
                }
            }
            return '';
        }

        isValidRoom(roomNumber) {
            // 房间号存在且不为"0"才是有效房间
            return roomNumber && roomNumber !== '0';
        }

        getCurrentTeamMember(roomElement) {
            // 队员信息在 .user-list 下的第二个 <p> 元素中
            const teamRow = roomElement.querySelector('.user-list p:nth-child(2)');
            if (!teamRow) return '';

            const teamNickname = teamRow.querySelector('span.nickname');
            if (!teamNickname) return '';

            // 获取昵称文本,如果为空则返回空字符串
            const nickname = teamNickname.textContent.trim();
            return nickname || '';
        }

        autoStartBattle(teamMember, roomNumber) {
            if (this.battleStarted) {
                console.log('[战魂觉醒自动战斗] ⚠️ 此房间已经开始过战斗,跳过');
                return;
            }

            console.log(`[战魂觉醒自动战斗] ⚔️ 准备自动开始战斗 - 房间:${roomNumber}, 队员:${teamMember}`);
            const battleButton = this.findStartBattleButton();
            if (battleButton) {
                console.log('[战魂觉醒自动战斗] 🚀 自动点击开始战斗按钮');
                battleButton.click();
                this.battleStarted = true; // 标记此房间已经开始战斗
                console.log('[战魂觉醒自动战斗] ✅ 战斗已开始,等待房间状态变化...');
            } else {
                console.log('[战魂觉醒自动战斗] ⚠️ 未找到可用的开始战斗按钮');
            }
        }

        // 优化后的按钮定位函数:只在房间容器内寻找
        findStartBattleButton() {
            const roomContainer = this.roomElement;
            if (!roomContainer) return null;

            // 根据您提供的 HTML 结构,开始战斗按钮位于 roomContainer (in-room border-wrap) 内部
            // 寻找成功按钮 (el-button--success) 且包含 "开始战斗" 文本的按钮

            // 遍历 roomContainer 内部的所有按钮,进行精确筛选
            const allButtons = roomContainer.querySelectorAll('.el-button');
            for (let button of allButtons) {
                const textContent = button.textContent.trim();

                if (textContent.includes('开始战斗') &&
                    button.classList.contains('el-button--success')) {

                    // 检查按钮是否可点击
                    if (this.isButtonClickable(button)) {
                        return button;
                    }
                }
            }

            return null;
        }

        // 保持原脚本中的 isButtonClickable 检查
        isButtonClickable(button) {
            if (!button) return false;
            return !button.disabled &&
                    button.getAttribute('aria-disabled') !== 'true' &&
                    button.style.display !== 'none' &&
                    !button.classList.contains('is-disabled');
        }

        destroy() {
            if (this.checkInterval) {
                clearInterval(this.checkInterval);
                this.checkInterval = null;
            }
            if (this.injectedButton) {
                this.injectedButton.remove();
                this.injectedButton = null;
            }
            console.log('[战魂觉醒自动战斗] 🔄 脚本已销毁');
        }
    }

    let autoBattleHelper = null;
    function initAutoBattle() {
        if (autoBattleHelper) {
            autoBattleHelper.destroy();
        }
        // 延迟初始化,确保页面元素加载
        setTimeout(() => {
            autoBattleHelper = new AutoBattleHelper();
        }, 2000);
    }

    let lastUrl = location.href;
    // 使用 MutationObserver 监听 URL 变化,处理 SPA 导航
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            console.log('[战魂觉醒自动战斗] 页面URL变化,重新初始化');
            // 延迟重新初始化,给页面留出加载时间
            setTimeout(initAutoBattle, 1000);
        }
    }).observe(document, { subtree: true, childList: true });

    window.addEventListener('beforeunload', () => {
        if (autoBattleHelper) {
            autoBattleHelper.destroy();
        }
    });

    // 首次加载时初始化
    console.log('[战魂觉醒自动战斗] 油猴脚本已加载完成');
    initAutoBattle();
})();