MZ - Player Ratings on Transfer Page

Displays player ratings on transfer page

目前為 2025-03-09 提交的版本,檢視 最新版本

// ==UserScript==
// @name          MZ - Player Ratings on Transfer Page
// @namespace     douglaskampl
// @version       1.3
// @description   Displays player ratings on transfer page
// @author        Douglas
// @match         https://www.managerzone.com/?p=transfer
// @match         https://www.managerzone.com/?p=players
// @icon          https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
// @grant         GM_addStyle
// @run-at        document-idle
// @license       MIT
// ==/UserScript==

(function () {
    'use strict';

    const ratings = {
        "SPEED": { "K": 0.09, "D": 0.25, "A": 0.25, "M": 0.15, "W": 0.25, "F": 0.23 },
        "STAMINA": { "K": 0.09, "D": 0.16, "A": 0.18, "M": 0.15, "W": 0.20, "F": 0.15 },
        "PLAYINT": { "K": 0.09, "D": 0.07, "A": 0.05, "M": 0.10, "W": 0.06, "F": 0.05 },
        "PASSING": { "K": 0.02, "D": 0.02, "A": 0.05, "M": 0.15, "W": 0.04, "F": 0.04 },
        "SHOOTING": { "K": 0.00, "D": 0.00, "A": 0.00, "M": 0.00, "W": 0.05, "F": 0.28 },
        "HEADING": { "K": 0.00, "D": 0.00, "A": 0.02, "M": 0.00, "W": 0.00, "F": 0.03 },
        "GOALKEEPING": { "K": 0.55, "D": 0.00, "A": 0.00, "M": 0.00, "W": 0.00, "F": 0.00 },
        "BALLCONTROL": { "K": 0.09, "D": 0.08, "A": 0.10, "M": 0.12, "W": 0.15, "F": 0.15 },
        "TACKLING": { "K": 0.00, "D": 0.30, "A": 0.25, "M": 0.20, "W": 0.05, "F": 0.02 },
        "CROSSING": { "K": 0.02, "D": 0.07, "A": 0.05, "M": 0.08, "W": 0.15, "F": 0.00 },
        "SETPLAYS": { "K": 0.00, "D": 0.00, "A": 0.00, "M": 0.00, "W": 0.00, "F": 0.00 },
        "EXPERIENCE": { "K": 0.05, "D": 0.05, "A": 0.05, "M": 0.05, "W": 0.05, "F": 0.05 }
    };

    const skillPositionMap = [
        "SPEED",
        "STAMINA",
        "PLAYINT",
        "PASSING",
        "SHOOTING",
        "HEADING",
        "GOALKEEPING",
        "BALLCONTROL",
        "TACKLING",
        "CROSSING",
        "SETPLAYS",
        "EXPERIENCE"
    ];

    function calculateRatings(skills) {
        const player = {
            K: 0,
            D: 0,
            A: 0,
            M: 0,
            W: 0,
            F: 0,
            B: 0,
            top: 0
        };

        Object.entries(skills).forEach(([skill, value]) => {
            if (!ratings[skill]) return;

            const num = parseInt(value, 10);
            if (isNaN(num)) return;

            if (skill !== "EXPERIENCE") {
                player.B += num;
            }

            player.K += num * ratings[skill]["K"];
            if (player.K > player.top) player.top = player.K;

            player.D += num * ratings[skill]["D"];
            if (player.D > player.top) player.top = player.D;

            player.A += num * ratings[skill]["A"];
            if (player.A > player.top) player.top = player.A;

            player.M += num * ratings[skill]["M"];
            if (player.M > player.top) player.top = player.M;

            player.W += num * ratings[skill]["W"];
            if (player.W > player.top) player.top = player.W;

            player.F += num * ratings[skill]["F"];
            if (player.F > player.top) player.top = player.F;
        });

        return {
            K: player.K.toFixed(2),
            D: player.D.toFixed(2),
            A: player.A.toFixed(2),
            M: player.M.toFixed(2),
            W: player.W.toFixed(2),
            F: player.F.toFixed(2),
            B: player.B,
            top: player.top.toFixed(2)
        };
    }

    function extractPlayerSkills(playerElement) {
        const skills = {};
        const skillRows = playerElement.querySelectorAll('.player_skills tr');

        skillRows.forEach((row, index) => {
            if (index >= skillPositionMap.length) return;

            const valueElem = row.querySelector('.skillval span');
            if (valueElem) {
                const skillType = skillPositionMap[index];
                const value = valueElem.textContent.trim();
                skills[skillType] = value;
            }
        });

        return skills;
    }

    function createRatingDisplay(ratings) {
        const positions = [
            { code: 'K', name: 'Goalkeeper', value: ratings.K },
            { code: 'D', name: 'Defender', value: ratings.D },
            { code: 'A', name: 'Anchorman', value: ratings.A },
            { code: 'M', name: 'Midfielder', value: ratings.M },
            { code: 'W', name: 'Winger', value: ratings.W },
            { code: 'F', name: 'Forward', value: ratings.F }
        ];

        const container = document.createElement('div');
        container.className = 'mz-rating-container';

        const ratingsList = document.createElement('div');
        ratingsList.className = 'mz-rating-list';

        positions.forEach(pos => {
            const row = document.createElement('div');
            row.className = 'mz-rating-row';

            const isTop = pos.value === ratings.top;

            const posName = document.createElement('span');
            posName.className = 'mz-pos-name' + (isTop ? ' mz-pos-top' : '');
            posName.textContent = pos.name + ':';

            const posValue = document.createElement('span');
            posValue.className = 'mz-pos-value' + (isTop ? ' mz-pos-top' : '');
            posValue.textContent = pos.value;

            row.appendChild(posName);
            row.appendChild(posValue);
            ratingsList.appendChild(row);
        });

        container.appendChild(ratingsList);

        return container;
    }

    function addRatingButton(playerElement) {
        const idElement = playerElement.querySelector('.player_id_span');
        if (!idElement) return;

        if (idElement.nextElementSibling && idElement.nextElementSibling.classList.contains('mz-rating-btn')) {
            return;
        }

        const btn = document.createElement('button');
        btn.className = 'mz-rating-btn';
        btn.innerHTML = '<i class="fa-solid fa-calculator"></i>';
        btn.title = 'Show player ratings';

        let ratingContainer = null;
        let isVisible = false;

        btn.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();

            if (isVisible && ratingContainer) {
                ratingContainer.classList.remove('mz-rating-visible');
                setTimeout(() => {
                    if (ratingContainer && ratingContainer.parentNode) {
                        ratingContainer.parentNode.removeChild(ratingContainer);
                    }
                    ratingContainer = null;
                }, 300);
                isVisible = false;

                btn.innerHTML = '<i class="fa-solid fa-calculator"></i>';
                return;
            }

            const skills = extractPlayerSkills(playerElement);
            const ratings = calculateRatings(skills);

            ratingContainer = createRatingDisplay(ratings);

            const playerHeader = playerElement.querySelector('.subheader');
            if (playerHeader) {
                playerHeader.parentNode.insertBefore(ratingContainer, playerHeader.nextSibling);
            } else {
                playerElement.appendChild(ratingContainer);
            }

            setTimeout(() => {
                ratingContainer.classList.add('mz-rating-visible');
            }, 10);

            isVisible = true;
            btn.innerHTML = '<i class="fa-solid fa-xmark"></i>';
        });

        idElement.parentNode.insertBefore(btn, idElement.nextSibling);
    }

    function processPlayerElements() {
        const playerContainers = document.querySelectorAll('div[id^="thePlayers_"]');
        playerContainers.forEach(addRatingButton);
    }

    function setUpObserver() {
        const playerContainer = document.getElementById('players_container') || document.body;

        const observer = new MutationObserver((mutations) => {
            let shouldProcess = false;

            mutations.forEach(mutation => {
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE &&
                            (node.id && node.id.startsWith('thePlayers_') ||
                             node.querySelector && node.querySelector('div[id^="thePlayers_"]'))) {
                            shouldProcess = true;
                            break;
                        }
                    }
                }
            });

            if (shouldProcess) {
                processPlayerElements();
            }
        });

        observer.observe(playerContainer, { childList: true, subtree: true });

        return observer;
    }

    function addStyles() {
        GM_addStyle(`
            .mz-rating-btn {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                margin-left: 8px;
                width: 24px;
                height: 24px;
                border: none;
                border-radius: 50%;
                background: #1a73e8;
                color: white;
                cursor: pointer;
                font-size: 12px;
                transition: all 0.2s ease;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }

            .mz-rating-btn:hover {
                background: #0d5bbb;
                transform: translateY(-1px);
                box-shadow: 0 3px 6px rgba(0, 0, 0, 0.25);
            }

            .mz-rating-container {
                margin: 10px 0;
                padding: 12px;
                background: white;
                border-radius: 8px;
                box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                max-width: 300px;
                opacity: 0;
                transform: translateY(-10px);
                transition: all 0.3s ease;
            }

            .mz-rating-visible {
                opacity: 1;
                transform: translateY(0);
            }

            .mz-rating-header {
                font-weight: bold;
                margin-bottom: 8px;
                padding-bottom: 5px;
                border-bottom: 1px solid #eee;
                color: #333;
                font-size: 14px;
            }

            .mz-rating-list {
                display: grid;
                grid-template-columns: repeat(2, 1fr);
                gap: 8px;
                margin-bottom: 10px;
            }

            .mz-rating-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 3px 5px;
            }

            .mz-pos-name {
                font-size: 13px;
                color: #555;
            }

            .mz-pos-value {
                font-weight: bold;
                font-size: 13px;
                color: #333;
            }

            .mz-pos-top {
                color: #1a73e8;
            }

            .mz-total-row {
                margin-top: 5px;
                padding-top: 8px;
                border-top: 1px solid #eee;
            }
        `);
    }

    function init() {
        addStyles();
        processPlayerElements();
        setUpObserver();
    }

    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(init, 500);
    } else {
        window.addEventListener('DOMContentLoaded', () => setTimeout(init, 500));
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址