Greasy Fork

Greasy Fork is available in English.

[MWI] Ultimate Enhancement Notifier v2.5 (Styled)

Adds floating UI and toggle buttons with DPS panel styling

当前为 2025-04-05 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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");
})();