- // ==UserScript==
- // @name MZ - Player Ratings on Transfer Page
- // @namespace douglaskampl
- // @version 1.0
- // @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
- // @license MIT
- // @run-at document-idle
- // ==/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));
- }
- })();