您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Adds floating UI and toggle buttons with DPS panel styling
当前为
// ==UserScript== // @name [MWI] Ultimate Enhancement Notifier v2.5 (Styled) // @namespace http://tampermonkey.net/ // @version 2.5 // @description Adds floating UI and toggle buttons with DPS panel styling // @author Truth_Light (modified by Nex, styled by Cosmic) // @match https://www.milkywayidle.com/* // @match https://test.milkywayidle.com/* // @license MIT // @grant GM_registerMenuCommand // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com // ==/UserScript== (function() { 'use strict'; // ====================== // STYLE CONFIGURATION // ====================== const STYLE = { colors: { primary: '#0078d4', background: 'rgba(0, 0, 0, 0.7)', border: '1px solid rgba(255, 255, 255, 0.2)', textPrimary: '#ffffff', textSecondary: '#a0a0b0', accent: '#4a8cff', danger: '#ff4a4a', success: '#4aff8c', headerBg: 'rgba(0, 0, 0, 0.5)', epic: '#9933FF', legendary: '#FF8C00', mythic: '#FF3333', blessed: 'linear-gradient(135deg, #FFD700, #FFFFFF, #FFD700)' }, fonts: { primary: '14px "Segoe UI", Roboto, sans-serif', secondary: '12px "Segoe UI", Roboto, sans-serif', header: 'bold 16px "Segoe UI", Roboto, sans-serif', milestone: 'bold 18px "Segoe UI", Roboto, sans-serif' }, shadows: { panel: '0 4px 12px rgba(0, 0, 0, 0.3)', notification: '0 2px 8px rgba(0,0,0,0.3)', milestone: '0 2px 12px rgba(0,0,0,0.4)', text: '1px 1px 2px rgba(0,0,0,0.5)' }, borderRadius: { medium: '16px', small: '8px' }, transitions: { fast: 'all 0.2s ease', medium: 'all 0.3s ease', slow: 'all 0.5s ease' } }; // Core Variables const userLanguage = localStorage.getItem('i18nextLng'); let enhancementLevel; let currentEnhancingIndex = 1; let enhancementData = { [currentEnhancingIndex]: { "强化数据": {}, "其他数据": {} } }; let item_name_to_hrid; let item_hrid_to_name; const isZH = userLanguage.startsWith("zh"); // ====================== // NOTIFICATION SYSTEM // ====================== function createNotificationContainer(headerElement) { const container = document.createElement("div"); container.id = "enhancementNotificationContainer"; Object.assign(container.style, { position: "absolute", top: "calc(100% + 5px)", left: "50%", transform: "translateX(-50%)", zIndex: "9999", display: "flex", flexDirection: "column", gap: "5px", width: "220px", pointerEvents: "none" }); if (getComputedStyle(headerElement).position === "static") { headerElement.style.position = "relative"; } headerElement.appendChild(container); return container; } function showNotification(message, type, level, isBlessed = false) { const headerElement = document.querySelector('[class^="Header_myActions"]'); if (!headerElement) return; let container = document.getElementById("enhancementNotificationContainer"); if (!container) { container = createNotificationContainer(headerElement); } if (type === "success") { createStandardNotification(container, level, isBlessed); if (level >= 10) { setTimeout(() => { createMilestoneNotification(container, level); }, 300); } } else { createFailureNotification(container); } } function createStandardNotification(container, level, isBlessed) { const notification = document.createElement("div"); notification.className = "enhancement-notification standard"; Object.assign(notification.style, { padding: "10px 15px", borderRadius: STYLE.borderRadius.small, color: "white", fontWeight: "bold", boxShadow: STYLE.shadows.notification, transform: "translateY(-20px)", opacity: "0", transition: STYLE.transitions.medium, textAlign: "center", marginBottom: "5px", position: "relative", overflow: "hidden", pointerEvents: "auto", textShadow: STYLE.shadows.text }); if (isBlessed) { Object.assign(notification.style, { background: STYLE.colors.blessed, color: "#8B4513" }); notification.textContent = isZH ? `祝福强化! +${level}` : `BLESSED! +${level}`; addHolyEffects(notification); } else { notification.style.background = getLevelGradient(level); notification.textContent = isZH ? `强化成功 +${level}` : `Success +${level}`; } animateNotification(notification, container, level, isBlessed); } function createMilestoneNotification(container, level) { const milestone = document.createElement("div"); milestone.className = "enhancement-notification milestone"; Object.assign(milestone.style, { padding: "12px 15px", borderRadius: STYLE.borderRadius.small, color: "white", fontWeight: "bolder", boxShadow: STYLE.shadows.milestone, transform: "translateY(-20px)", opacity: "0", transition: STYLE.transitions.medium, textAlign: "center", marginBottom: "5px", animation: "pulse 2s infinite", position: "relative", overflow: "hidden", pointerEvents: "auto", textShadow: STYLE.shadows.text, font: STYLE.fonts.milestone }); if (level >= 20) { milestone.style.background = `linear-gradient(135deg, ${STYLE.colors.mythic}, #FF0000)`; milestone.style.textShadow = "0 0 8px rgba(255, 0, 0, 0.8)"; milestone.textContent = isZH ? "命中注定!" : "IT. IS. DESTINY."; } else if (level >= 15) { milestone.style.background = `linear-gradient(135deg, ${STYLE.colors.legendary}, #FF6600)`; milestone.style.textShadow = "0 0 8px rgba(255, 102, 0, 0.8)"; milestone.textContent = isZH ? "奇迹发生!" : "IT'S A MIRACLE!"; } else if (level >= 10) { milestone.style.background = `linear-gradient(135deg, ${STYLE.colors.epic}, #8000FF)`; milestone.style.textShadow = "0 0 8px rgba(153, 51, 255, 0.8)"; milestone.textContent = isZH ? "运气不错!" : "NICE LUCK!"; } animateNotification(milestone, container, level, false); } function createFailureNotification(container) { const notification = document.createElement("div"); notification.className = "enhancement-notification failure"; Object.assign(notification.style, { padding: "10px 15px", borderRadius: STYLE.borderRadius.small, color: "white", fontWeight: "bold", boxShadow: STYLE.shadows.notification, transform: "translateY(-20px)", opacity: "0", transition: STYLE.transitions.medium, textAlign: "center", marginBottom: "5px", position: "relative", overflow: "hidden", pointerEvents: "auto", textShadow: STYLE.shadows.text, backgroundColor: STYLE.colors.danger, borderTop: "3px solid #C62828" }); notification.textContent = isZH ? "强化失败!" : "Failed!"; animateNotification(notification, container, 0, false); } function animateNotification(notification, container, level, isBlessed) { container.appendChild(notification); setTimeout(() => { notification.style.transform = "translateY(0)"; notification.style.opacity = "1"; }, 10); setTimeout(() => { notification.style.transform = "translateY(20px)"; notification.style.opacity = "0"; setTimeout(() => notification.remove(), 300); }, getNotificationDuration(level, isBlessed)); notification.addEventListener("click", () => { notification.style.transform = "translateY(20px)"; notification.style.opacity = "0"; setTimeout(() => notification.remove(), 300); }); } function addHolyEffects(notification) { const rays = document.createElement("div"); rays.className = "holy-rays"; Object.assign(rays.style, { position: "absolute", top: "0", left: "0", width: "100%", height: "100%", background: "radial-gradient(circle, transparent 20%, rgba(255,215,0,0.3) 70%)", pointerEvents: "none", animation: "raysRotate 4s linear infinite" }); notification.appendChild(rays); for (let i = 0; i < 4; i++) { const cross = document.createElement("div"); cross.textContent = "✝"; Object.assign(cross.style, { position: "absolute", fontSize: "16px", animation: `floatUp ${3 + Math.random() * 2}s linear infinite`, opacity: "0.7", left: `${10 + (i * 25)}%`, top: "100%" }); notification.appendChild(cross); } } function getLevelGradient(level) { if (level >= 20) { return `linear-gradient(135deg, ${STYLE.colors.mythic}, #FF0000)`; } else if (level >= 15) { return `linear-gradient(135deg, ${STYLE.colors.legendary}, #FF6600)`; } else if (level >= 10) { return `linear-gradient(135deg, ${STYLE.colors.epic}, #8000FF)`; } else if (level >= 5) { return "linear-gradient(135deg, #3399FF, #0066FF)"; } else if (level >= 1) { return "linear-gradient(135deg, #33CC33, #009900)"; } else { return "linear-gradient(135deg, #CCCCCC, #999999)"; } } function getNotificationDuration(level, isBlessed) { if (isBlessed) return 5000; if (level >= 20) return 5000; if (level >= 15) return 4000; if (level >= 10) return 3000; return 2500; } // ====================== // ENHANCEMENT TRACKING // ====================== function hookWS() { const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data"); const oriGet = dataProperty.get; dataProperty.get = hookedGet; Object.defineProperty(MessageEvent.prototype, "data", dataProperty); function hookedGet() { const socket = this.currentTarget; if (!(socket instanceof WebSocket)) return oriGet.call(this); if (!socket.url.includes("api.milkywayidle.com/ws") && !socket.url.includes("api-test.milkywayidle.com/ws")) { return oriGet.call(this); } const message = oriGet.call(this); Object.defineProperty(this, "data", { value: message }); return handleMessage(message); } } function handleMessage(message) { try { const obj = JSON.parse(message); if (!obj) return message; if (obj.type === "init_character_data") { handleInitData(); } else if (obj.type === "action_completed" && obj.endCharacterAction?.actionHrid === "/actions/enhancing/enhance") { handleEnhancement(obj.endCharacterAction); } } catch (error) { console.error("Error processing message:", error); } return message; } function handleInitData() { const initClientData = localStorage.getItem('initClientData'); if (!initClientData) return; try { const data = JSON.parse(initClientData); if (data.type !== 'init_client_data') return; item_hrid_to_name = data.itemDetailMap; for (const key in item_hrid_to_name) { if (item_hrid_to_name[key]?.name) { item_hrid_to_name[key] = item_hrid_to_name[key].name; } } item_name_to_hrid = Object.fromEntries( Object.entries(item_hrid_to_name).map(([key, value]) => [value, key]) ); } catch (error) { console.error('数据解析失败:', error); } } function handleEnhancement(action) { const newLevel = parseInt(action.primaryItemHash.match(/::(\d+)$/)[1]); const targetLevel = action.enhancingMaxLevel; const currentCount = action.currentCount; const wasBlessed = enhancementLevel !== undefined && (newLevel - enhancementLevel) >= 2; if (enhancementLevel !== undefined) { if (currentCount < enhancementData[currentEnhancingIndex]["强化次数"]) { startNewEnhancementSession(); return; } const currentItem = enhancementData[currentEnhancingIndex]["强化数据"]; if (!currentItem[enhancementLevel]) { currentItem[enhancementLevel] = { "成功次数": 0, "失败次数": 0, "成功率": 0 }; } if (newLevel > enhancementLevel) { handleSuccess(currentItem, newLevel, wasBlessed); } else { handleFailure(action, currentItem); } if (newLevel >= targetLevel) { showTargetAchievedCelebration(newLevel, targetLevel); } updateStats(currentItem); enhancementData[currentEnhancingIndex]["强化状态"] = getEnhancementState(currentItem); } else { initializeNewItem(action, newLevel); } enhancementLevel = newLevel; enhancementData[currentEnhancingIndex]["强化次数"] = currentCount; updateDisplay(); updateFloatingUI(); } function startNewEnhancementSession() { currentEnhancingIndex++; enhancementData[currentEnhancingIndex] = { "强化数据": {}, "其他数据": {} }; enhancementLevel = undefined; } function handleSuccess(currentItem, newLevel, wasBlessed) { currentItem[enhancementLevel]["成功次数"]++; const message = isZH ? `强化成功 +${newLevel}` : `Success +${newLevel}`; showNotification( wasBlessed ? (isZH ? `祝福强化! +${newLevel}` : `BLESSED! +${newLevel}`) : message, "success", newLevel, wasBlessed ); } function handleFailure(action, currentItem) { currentItem[enhancementLevel]["失败次数"]++; showNotification(isZH ? "强化失败!" : "Failed!", "failure", 0); if (action.enhancingProtectionMinLevel >= 2 && enhancementLevel >= action.enhancingProtectionMinLevel) { enhancementData[currentEnhancingIndex]["其他数据"]["保护消耗总数"]++; } } function updateStats(currentItem) { const success = currentItem[enhancementLevel]["成功次数"]; const failure = currentItem[enhancementLevel]["失败次数"]; currentItem[enhancementLevel]["成功率"] = success / (success + failure); } function getEnhancementState(currentItem) { const highestSuccessLevel = Math.max(...Object.keys(currentItem).filter(level => currentItem[level]["成功次数"] > 0)); return (highestSuccessLevel + 1 >= enhancementData[currentEnhancingIndex]["其他数据"]["目标强化等级"]) ? "强化成功" : "强化失败"; } function initializeNewItem(action, newLevel) { const itemName = item_hrid_to_name[action.primaryItemHash.match(/::([^:]+)::[^:]*$/)[1]]; enhancementData[currentEnhancingIndex]["其他数据"] = { "物品名称": itemName, "目标强化等级": action.enhancingMaxLevel, "保护消耗总数": 0, }; } function showTargetAchievedCelebration(achievedLevel, targetLevel) { const celebration = document.createElement("div"); celebration.id = "enhancementCelebration"; Object.assign(celebration.style, { position: "fixed", top: "0", left: "0", width: "100%", height: "100%", zIndex: "99999", pointerEvents: "none", display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", background: "radial-gradient(circle, rgba(0,0,0,0.7), transparent 70%)" }); const text = document.createElement("div"); text.textContent = isZH ? `目标达成! +${achievedLevel}` : `TARGET ACHIEVED! +${achievedLevel}`; Object.assign(text.style, { fontSize: "3rem", fontWeight: "900", color: "#FFD700", textShadow: "0 0 20px #FF0000, 0 0 30px #FF8C00", animation: "celebrateText 2s ease-out both" }); celebration.appendChild(text); for (let i = 0; i < 100; i++) { const confetti = document.createElement("div"); Object.assign(confetti.style, { position: "absolute", width: "10px", height: "10px", backgroundColor: getRandomColor(), borderRadius: "50%", left: "50%", top: "50%", opacity: "0", animation: `confettiFly ${Math.random() * 2 + 1}s ease-out ${Math.random() * 0.5}s both` }); celebration.appendChild(confetti); } for (let i = 0; i < 8; i++) { setTimeout(() => { createFireworkBurst(celebration); }, i * 300); } document.body.appendChild(celebration); setTimeout(() => { celebration.style.opacity = "0"; celebration.style.transition = "opacity 1s ease-out"; setTimeout(() => celebration.remove(), 1000); }, 4000); } function createFireworkBurst(container) { const burst = document.createElement("div"); Object.assign(burst.style, { position: "absolute", left: `${Math.random() * 80 + 10}%`, top: `${Math.random() * 80 + 10}%`, width: "5px", height: "5px", borderRadius: "50%", background: getRandomColor(), boxShadow: `0 0 10px 5px ${getRandomColor()}`, animation: `fireworkExpand 0.8s ease-out both` }); container.appendChild(burst); for (let i = 0; i < 30; i++) { setTimeout(() => { const particle = document.createElement("div"); Object.assign(particle.style, { position: "absolute", left: burst.style.left, top: burst.style.top, width: "3px", height: "3px", backgroundColor: burst.style.background, borderRadius: "50%", animation: `fireworkTrail ${Math.random() * 0.5 + 0.5}s ease-out both` }); container.appendChild(particle); }, i * 20); } } function getRandomColor() { const colors = ["#FF0000", "#FF8C00", "#FFD700", "#4CAF50", "#2196F3", "#9C27B0"]; return colors[Math.floor(Math.random() * colors.length)]; } // ====================== // DISPLAY SYSTEM // ====================== function updateDisplay() { const targetElement = document.querySelector(".SkillActionDetail_enhancingComponent__17bOx"); if (!targetElement) return; let parentContainer = document.querySelector("#enhancementParentContainer"); if (!parentContainer) { parentContainer = createDisplayContainer(targetElement); } updateDropdown(parentContainer); } function createDisplayContainer(targetElement) { const parentContainer = document.createElement("div"); parentContainer.id = "enhancementParentContainer"; Object.assign(parentContainer.style, { display: "block", borderLeft: `2px solid ${STYLE.colors.border}`, padding: "0 4px" }); const title = document.createElement("div"); title.textContent = isZH ? "强化数据" : "Enhancement Data"; Object.assign(title.style, { fontWeight: "bold", marginBottom: "10px", textAlign: "center", color: STYLE.colors.textSecondary, font: STYLE.fonts.header }); parentContainer.appendChild(title); const dropdownContainer = document.createElement("div"); dropdownContainer.style.marginBottom = "10px"; const dropdown = document.createElement("select"); dropdown.id = "enhancementDropdown"; Object.assign(dropdown.style, { width: "100%", padding: "4px", borderRadius: STYLE.borderRadius.small, background: STYLE.colors.background, color: STYLE.colors.textPrimary, border: STYLE.colors.border }); dropdown.addEventListener("change", function() { renderStats(this.value); updateDropdownColor(); }); dropdownContainer.appendChild(dropdown); parentContainer.appendChild(dropdownContainer); const statsContainer = document.createElement("div"); statsContainer.id = "enhancementStatsContainer"; Object.assign(statsContainer.style, { display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: "10px", textAlign: "center", marginTop: "10px", font: STYLE.fonts.secondary }); parentContainer.appendChild(statsContainer); targetElement.appendChild(parentContainer); return parentContainer; } function updateDropdown(parentContainer) { const dropdown = parentContainer.querySelector("#enhancementDropdown"); const previousSelectedValue = dropdown.value; dropdown.innerHTML = ""; Object.keys(enhancementData).forEach(key => { const item = enhancementData[key]; if (!item["其他数据"]) return; const option = document.createElement("option"); const itemName = item["其他数据"]["物品名称"] || "Unknown"; const targetLevel = item["其他数据"]["目标强化等级"] || 0; const currentLevel = Math.max(...Object.keys(item["强化数据"] || {}).map(Number).filter(n => !isNaN(n))) || 0; const enhancementState = item["强化状态"] || ""; option.text = isZH ? `${itemName} (目标: ${targetLevel}, 总计: ${item["强化次数"] || 0}${item["其他数据"]["保护消耗总数"] > 0 ? `, 垫子: ${item["其他数据"]["保护消耗总数"]}` : ""})` : `${itemName} (Target: ${targetLevel}, Total: ${item["强化次数"] || 0}${item["其他数据"]["保护消耗总数"] > 0 ? `, Protectors: ${item["其他数据"]["保护消耗总数"]}` : ""})`; option.value = key; option.style.color = enhancementState === "强化成功" ? STYLE.colors.success : (currentLevel < targetLevel && Object.keys(enhancementData).indexOf(key) === Object.keys(enhancementData).length - 1) ? STYLE.colors.accent : STYLE.colors.danger; dropdown.appendChild(option); }); if (Object.keys(enhancementData).length > 0) { dropdown.value = previousSelectedValue || Object.keys(enhancementData)[0]; updateDropdownColor(); renderStats(dropdown.value); } } function updateDropdownColor() { const dropdown = document.querySelector("#enhancementDropdown"); if (!dropdown) return; const selectedOption = dropdown.options[dropdown.selectedIndex]; dropdown.style.color = selectedOption ? selectedOption.style.color : STYLE.colors.textPrimary; } function renderStats(selectedKey) { const statsContainer = document.querySelector("#enhancementStatsContainer"); if (!statsContainer) return; statsContainer.innerHTML = ""; const item = enhancementData[selectedKey]; if (!item || !item["强化数据"]) return; const headers = ["等级", "成功", "失败", "概率"]; headers.forEach(headerText => { const headerDiv = document.createElement("div"); headerDiv.style.fontWeight = "bold"; headerDiv.textContent = isZH ? headerText : headerText === "等级" ? "Level" : headerText === "成功" ? "Success" : headerText === "失败" ? "Failure" : "Success Rate"; statsContainer.appendChild(headerDiv); }); const totalSuccess = Object.values(item["强化数据"]).reduce((acc, val) => acc + (val["成功次数"] || 0), 0); const totalFailure = Object.values(item["强化数据"]).reduce((acc, val) => acc + (val["失败次数"] || 0), 0); const totalCount = totalSuccess + totalFailure; const totalRate = totalCount > 0 ? (totalSuccess / totalCount * 100).toFixed(2) : "0.00"; ["总计", totalSuccess, totalFailure, `${totalRate}%`].forEach((totalText, index) => { const totalDiv = document.createElement("div"); totalDiv.textContent = isZH ? totalText : index === 0 ? "Total" : totalText; statsContainer.appendChild(totalDiv); }); Object.keys(item["强化数据"]) .map(Number) .sort((a, b) => b - a) .forEach(level => { const levelData = item["强化数据"][level]; const levelDivs = [ level, levelData["成功次数"] || 0, levelData["失败次数"] || 0, `${((levelData["成功率"] || 0) * 100).toFixed(2)}%` ]; levelDivs.forEach(data => { const dataDiv = document.createElement("div"); dataDiv.textContent = data; statsContainer.appendChild(dataDiv); }); }); } // ====================== // FLOATING UI (UPDATED) // ====================== function createFloatingUI() { const floatingUI = document.createElement("div"); floatingUI.id = "enhancementFloatingUI"; Object.assign(floatingUI.style, { position: "fixed", top: "50px", left: "50px", zIndex: "9998", fontSize: "14px", padding: "0", borderRadius: STYLE.borderRadius.medium, boxShadow: STYLE.shadows.panel, overflow: "hidden", width: "320px", minHeight: "auto", background: STYLE.colors.background, border: `1px solid ${STYLE.colors.border}`, color: STYLE.colors.textPrimary }); // Header with drag and toggle functionality const header = document.createElement("div"); header.id = "enhancementPanelHeader"; Object.assign(header.style, { display: "flex", justifyContent: "space-between", alignItems: "center", cursor: "move", padding: "10px 15px", background: STYLE.colors.headerBg, borderBottom: `1px solid ${STYLE.colors.border}` }); const title = document.createElement("span"); title.textContent = isZH ? "强化追踪器" : "Enhancement Tracker"; title.style.fontWeight = "bold"; const closeBtn = document.createElement("button"); closeBtn.textContent = isZH ? "收起" : "Hide"; Object.assign(closeBtn.style, { backgroundColor: STYLE.colors.primary, color: "white", border: "none", padding: "5px 10px", borderRadius: "4px", cursor: "pointer" }); header.appendChild(title); header.appendChild(closeBtn); floatingUI.appendChild(header); // Content area const content = document.createElement("div"); content.id = "enhancementPanelContent"; Object.assign(content.style, { padding: "15px", maxHeight: "500px", overflowY: "auto" }); floatingUI.appendChild(content); // Drag functionality let isDragging = false; let offsetX, offsetY; header.addEventListener("mousedown", (e) => { isDragging = true; offsetX = e.clientX - floatingUI.offsetLeft; offsetY = e.clientY - floatingUI.offsetTop; }); document.addEventListener("mousemove", (e) => { if (!isDragging) return; floatingUI.style.left = `${e.clientX - offsetX}px`; floatingUI.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener("mouseup", () => { isDragging = false; }); // Toggle functionality closeBtn.addEventListener("click", () => { const isHidden = content.style.display === "none"; content.style.display = isHidden ? "block" : "none"; closeBtn.textContent = isHidden ? (isZH ? "收起" : "Hide") : (isZH ? "展开" : "Show"); localStorage.setItem("enhancementUIVisible", String(!isHidden)); }); // Initialize visibility const isVisible = localStorage.getItem("enhancementUIVisible") !== "false"; content.style.display = isVisible ? "block" : "none"; closeBtn.textContent = isVisible ? (isZH ? "收起" : "Hide") : (isZH ? "展开" : "Show"); document.body.appendChild(floatingUI); return floatingUI; } function updateFloatingUI() { const floatingUI = document.getElementById("enhancementFloatingUI") || createFloatingUI(); const content = document.getElementById("enhancementPanelContent"); if (currentEnhancingIndex === -1 || !enhancementData[currentEnhancingIndex]) { content.innerHTML = isZH ? "没有活跃的强化数据" : "No active enhancement data"; return; } const session = enhancementData[currentEnhancingIndex]; const totalAttempts = session["强化次数"]; const totalSuccess = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["成功次数"] || 0), 0); const totalFailure = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["失败次数"] || 0), 0); const totalRate = totalAttempts > 0 ? (totalSuccess / totalAttempts * 100).toFixed(2) : 0; // Generate HTML content content.innerHTML = ` <div style="margin-bottom: 15px;"> <div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> <span>${isZH ? "物品" : "Item"}:</span> <strong>${session["其他数据"]["物品名称"]}</strong> </div> <div style="display: flex; justify-content: space-between;"> <span>${isZH ? "目标等级" : "Target Level"}:</span> <span>${session["其他数据"]["目标强化等级"]}</span> </div> </div> <table style="width: 100%; border-collapse: collapse; margin-bottom: 15px;"> <thead> <tr style="border-bottom: 1px solid ${STYLE.colors.border}"> <th style="padding: 6px 0; text-align: left;">${isZH ? "等级" : "Level"}</th> <th style="padding: 6px 0; text-align: right;">${isZH ? "成功" : "Success"}</th> <th style="padding: 6px 0; text-align: right;">${isZH ? "失败" : "Failure"}</th> <th style="padding: 6px 0; text-align: right;">${isZH ? "概率" : "Rate"}</th> </tr> </thead> <tbody> ${Object.keys(session["强化数据"]) .sort((a, b) => b - a) .map(level => { const levelData = session["强化数据"][level]; const rate = ((levelData["成功率"] || 0) * 100).toFixed(2); return ` <tr ${level == enhancementLevel ? 'style="font-weight: bold;"' : ''}> <td style="padding: 6px 0;">${level}</td> <td style="padding: 6px 0; text-align: right;">${levelData["成功次数"] || 0}</td> <td style="padding: 6px 0; text-align: right;">${levelData["失败次数"] || 0}</td> <td style="padding: 6px 0; text-align: right;">${rate}%</td> </tr>`; }).join('')} </tbody> </table> <table style="width: 100%; border-collapse: collapse; border-top: 1px solid ${STYLE.colors.border}; padding-top: 10px;"> <tr> <td style="padding: 6px 0;">${isZH ? "总尝试" : "Total Attempts"}:</td> <td style="padding: 6px 0; text-align: right;">${totalAttempts}</td> </tr> <tr> <td style="padding: 6px 0;">${isZH ? "总成功" : "Total Success"}:</td> <td style="padding: 6px 0; text-align: right;">${totalSuccess}</td> </tr> <tr> <td style="padding: 6px 0;">${isZH ? "总失败" : "Total Failure"}:</td> <td style="padding: 6px 0; text-align: right;">${totalFailure}</td> </tr> <tr> <td style="padding: 6px 0;">${isZH ? "成功率" : "Success Rate"}:</td> <td style="padding: 6px 0; text-align: right;">${totalRate}%</td> </tr> ${session["其他数据"]["保护消耗总数"] > 0 ? ` <tr> <td style="padding: 6px 0;">${isZH ? "保护消耗" : "Protectors Used"}:</td> <td style="padding: 6px 0; text-align: right;">${session["其他数据"]["保护消耗总数"]}</td> </tr>` : ''} </table>`; } // ====================== // TESTING SYSTEM // ====================== function initializeTesting() { if (typeof GM_registerMenuCommand !== 'undefined') { GM_registerMenuCommand("🔧 Test Success Notifications", () => testNotifications("success")); GM_registerMenuCommand("🔧 Test Failure Notifications", () => testNotifications("failure")); GM_registerMenuCommand("✨ Test Blessed Success", () => testNotifications("blessed")); GM_registerMenuCommand("🌀 Test All Notifications", () => testNotifications("all")); } window.testEnhancement = { success: () => testNotifications("success"), allSuccess: () => testNotifications("allSuccess"), failure: () => testNotifications("failure"), blessed: () => testNotifications("blessed"), all: () => testNotifications("all"), custom: (level, type, targetLevel) => { const isBlessed = type === "blessed"; const isSuccess = type !== "failure"; showNotification( isBlessed ? "BLESSED!" : isSuccess ? "Success" : "Failed!", isSuccess ? "success" : "failure", level, isBlessed ); if (level >= targetLevel){ showTargetAchievedCelebration(level, targetLevel); } } }; } function testNotifications(type) { const tests = { success: [ { level: 1, blessed: false }, { level: 5, blessed: false }, { level: 10, blessed: false }, { level: 15, blessed: false }, { level: 20, blessed: false } ], allSuccess: [ { level: 1, blessed: false }, { level: 2, blessed: false }, { level: 3, blessed: false }, { level: 4, blessed: false }, { level: 5, blessed: false }, { level: 6, blessed: false }, { level: 7, blessed: false }, { level: 8, blessed: false }, { level: 9, blessed: false }, { level: 10, blessed: false }, { level: 11, blessed: false }, { level: 12, blessed: false }, { level: 13, blessed: false }, { level: 14, blessed: false }, { level: 15, blessed: false }, { level: 16, blessed: false }, { level: 17, blessed: false }, { level: 18, blessed: false }, { level: 19, blessed: false }, { level: 20, blessed: false } ], blessed: [ { level: 3, blessed: true }, { level: 8, blessed: true }, { level: 12, blessed: true }, { level: 17, blessed: true }, { level: 22, blessed: true } ], failure: [ { level: 0, blessed: false } ], all: [ { level: 1, blessed: false }, { level: 0, blessed: false }, { level: 3, blessed: true }, { level: 0, blessed: false }, { level: 10, blessed: false }, { level: 12, blessed: true }, { level: 15, blessed: false }, { level: 0, blessed: false }, { level: 20, blessed: false } ] }; tests[type].forEach((test, i) => { setTimeout(() => { const message = test.blessed ? (isZH ? `祝福强化! +${test.level}` : `BLESSED! +${test.level}`) : (test.level > 0 ? (isZH ? `强化成功 +${test.level}` : `Success +${test.level}`) : (isZH ? "强化失败!" : "Failed!")); showNotification( message, test.level > 0 ? "success" : "failure", test.level, test.blessed ); }, i * 800); }); } // ====================== // INITIALIZATION // ====================== function addGlobalStyles() { const style = document.createElement("style"); style.textContent = ` @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes holyGlow { 0% { box-shadow: 0 0 10px #FFD700; } 50% { box-shadow: 0 0 25px #FFD700, 0 0 40px white; } 100% { box-shadow: 0 0 10px #FFD700; } } @keyframes raysRotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes floatUp { 0% { transform: translateY(0) rotate(0deg); opacity: 0; } 10% { opacity: 0.7; } 90% { opacity: 0.7; } 100% { transform: translateY(-100px) rotate(20deg); opacity: 0; } } @keyframes celebrateText { 0% { transform: scale(0.5); opacity: 0; } 50% { transform: scale(1.2); opacity: 1; } 100% { transform: scale(1); } } @keyframes confettiFly { 0% { transform: translate(0,0) rotate(0deg); opacity: 1; } 100% { transform: translate(${Math.random() > 0.5 ? '-' : ''}${Math.random() * 300 + 100}px, ${Math.random() * 300 + 100}px) rotate(360deg); opacity: 0; } } @keyframes fireworkExpand { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(20); opacity: 0; } } @keyframes fireworkTrail { 0% { transform: translate(0,0); opacity: 1; } 100% { transform: translate(${Math.random() > 0.5 ? '-' : ''}${Math.random() * 100 + 50}px, ${Math.random() * 100 + 50}px); opacity: 0; } } .enhancement-notification { position: relative; overflow: hidden; transition: ${STYLE.transitions.medium}; } #enhancementFloatingUI { transition: ${STYLE.transitions.medium}; } #enhancementFloatingUI:hover { box-shadow: 0 6px 16px rgba(0,0,0,0.4); transform: translateY(-2px); } #enhancementPanelContent { max-height: 300px; overflow-y: auto; } #enhancementPanelContent::-webkit-scrollbar { width: 6px; } #enhancementPanelContent::-webkit-scrollbar-thumb { background-color: ${STYLE.colors.border}; border-radius: 3px; } `; document.head.appendChild(style); } function initializeFloatingUI() { const checkReady = setInterval(() => { if (document.body && typeof item_hrid_to_name !== "undefined") { clearInterval(checkReady); createFloatingUI(); addToggleControls(); updateFloatingUI(); } }, 500); } // Start everything addGlobalStyles(); initializeTesting(); initializeFloatingUI(); hookWS(); console.log("Enhancement Notifier v2.5 loaded - Styled version"); })();