您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Beautifies and groups DOTV battle logs with collapsible UI and functional buttons, including toggle for auto-hide.
// ==UserScript== // @name DOTV Battle Log Beautifier // @version 1.1 // @license MIT // @namespace https://greasyfork.org/users/1159361 // @description Beautifies and groups DOTV battle logs with collapsible UI and functional buttons, including toggle for auto-hide. // @author Zaregoto_Gaming // @match https://play.dragonsofthevoid.com/* // @grant none // ==/UserScript== (function () { 'use strict'; const processedAttr = 'data-beautified'; let autoCollapse = true; function enhanceLine(entry) { if (entry.hasAttribute(processedAttr)) return; let html = entry.innerHTML; // Detect group-start entries early and hide them if (/did ([\d,]+) damage/.test(html) || /crit ([\d,]+) damage/.test(html) || /strikes you for/.test(html) || /nimbly evaded/.test(html)) { entry.setAttribute('data-group-start', 'true'); entry.style.display = 'none'; } html = html.replace(/<span[^>]*?style="[^"]*?color: rgb\(33, 150, 243\)[^"]*?"[^>]*?>(.*?)<\/span>/g, '<strong style="color: #2196F3;">⚔️ $1</strong>'); html = html.replace(/contributed ([\d,]+) damage/g, '💥 <span style="color:red;font-weight:bold;">$1</span> damage'); html = html.replace(/did ([\d,]+) damage/g, '💥 did <span style="color:orange;font-weight:bold;">$1</span> damage'); html = html.replace(/crit ([\d,]+) damage/g, '❗<span style="color:#e91e63;font-weight:bold;">CRIT $1</span>'); html = html.replace(/restored ([\d,]+) of your Health/g, '❤️ <span style="color:green;font-weight:bold;">+$1 HP</span>'); html = html.replace(/reduced the damage(.*?)took/g, '🛡️ <em>damage mitigated</em>'); html = html.replace(/earned (\d+) experience/g, '🧠 <span style="color:#00bcd4;">+$1 XP</span>'); html = html.replace(/([^\s]+(?: [^\s]+)*) strikes you for ([\d,]+) damage/g, '🩸 $1 <span style="color:darkred;">attacks you for $2 damage</span>'); html = html.replace(/nimbly evaded(.*?)attack!/g, '🌀 <span style="color:#9c27b0;">Evaded the attack!</span>'); entry.innerHTML = html; entry.setAttribute(processedAttr, 'true'); } function makeCollapsibleGroup(startEntry) { const parent = startEntry.parentElement; if (!parent || startEntry.hasAttribute('data-collapsed')) return; const details = document.createElement('details'); details.className = 'log-group'; details.open = !autoCollapse; const summary = document.createElement('summary'); summary.innerHTML = startEntry.innerHTML; Object.assign(details.style, { border: '1px solid rgba(255,255,255,0.1)', borderRadius: '5px', padding: '4px', margin: '4px 0', background: 'rgba(255,255,255,0.03)', }); details.appendChild(summary); const nextSiblings = []; let next = startEntry.nextElementSibling; while (next && !next.hasAttribute('data-group-start')) { const temp = next.nextElementSibling; nextSiblings.push(next); next = temp; } nextSiblings.forEach(el => { details.appendChild(el); }); parent.insertBefore(details, startEntry.nextSibling); startEntry.style.display = 'none'; startEntry.setAttribute('data-collapsed', 'true'); } function collapseAllLogs(container) { container.querySelectorAll('.log-group').forEach(d => d.open = false); } function expandAllLogs(container) { container.querySelectorAll('.log-group').forEach(d => d.open = true); } function addGlobalControls(container) { const existing = container.parentElement.querySelector('.log-controls'); if (existing) existing.remove(); const controls = document.createElement('div'); controls.className = 'log-controls'; Object.assign(controls.style, { marginBottom: '8px', display: 'flex', gap: '10px' }); const collapseBtn = document.createElement('button'); collapseBtn.textContent = 'Collapse All'; collapseBtn.onclick = () => collapseAllLogs(container); const expandBtn = document.createElement('button'); expandBtn.textContent = 'Expand All'; expandBtn.onclick = () => expandAllLogs(container); const toggleAutoBtn = document.createElement('button'); toggleAutoBtn.textContent = `Auto-Hide: ${autoCollapse ? 'On' : 'Off'}`; toggleAutoBtn.onclick = () => { autoCollapse = !autoCollapse; toggleAutoBtn.textContent = `Auto-Hide: ${autoCollapse ? 'On' : 'Off'}`; }; [collapseBtn, expandBtn, toggleAutoBtn].forEach(btn => { Object.assign(btn.style, { padding: '4px 8px', background: '#333', color: '#fff', border: '1px solid #666', cursor: 'pointer', borderRadius: '4px', fontSize: '12px', }); }); controls.append(collapseBtn, expandBtn, toggleAutoBtn); container.parentElement.insertBefore(controls, container); } function fullScanAndGroup(container) { const entries = [...container.querySelectorAll(':scope > div')]; addGlobalControls(container); entries.forEach(enhanceLine); for (let i = 0; i < entries.length; i++) { const entry = entries[i]; if (entry.hasAttribute('data-group-start')) { makeCollapsibleGroup(entry); } } } function observeLog(container) { if (!container) return; const observer = new MutationObserver(mutations => { let needsGrouping = false; for (const mutation of mutations) { mutation.addedNodes.forEach(node => { if (!(node instanceof HTMLElement)) return; node.classList.add('invisible-log'); enhanceLine(node); needsGrouping = true; }); } if (needsGrouping) { setTimeout(() => { fullScanAndGroup(container); container.querySelectorAll('.invisible-log').forEach(el => el.classList.remove('invisible-log')); }, 10); } }); observer.observe(container, { childList: true }); } function initializeContainer(container) { if (!container || container.dataset.enhanced) return; container.dataset.enhanced = 'true'; observeLog(container); fullScanAndGroup(container); } const globalObserver = new MutationObserver(() => { const logs = document.querySelectorAll('.battle-log-container'); logs.forEach(initializeContainer); }); globalObserver.observe(document.body, { childList: true, subtree: true }); window.addEventListener('load', () => { document.querySelectorAll('.battle-log-container').forEach(initializeContainer); }); const style = document.createElement('style'); style.textContent = ` .battle-log-container details summary { cursor: pointer; list-style: revert; } .battle-log-container details { border: 1px solid rgba(255,255,255,0.1); border-radius: 5px; padding: 4px; margin: 4px 0; background: rgba(255,255,255,0.03); } .battle-log-container details > div { padding-left: 2.2em; } .invisible-log { display: none !important; } `; document.head.appendChild(style); })();