FMP Player Analyzer v7.0 (Fixed) - High RP Calibration

Hata Düzeltmesi: T değişkeni hatası giderildi. Yüksek Potansiyel (RP) tahmin katsayıları güncellendi.

当前为 2025-11-24 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         FMP Player Analyzer v7.0 (Fixed) - High RP Calibration
// @namespace    http://tampermonkey.net/
// @version      7.0.1
// @description  Hata Düzeltmesi: T değişkeni hatası giderildi. Yüksek Potansiyel (RP) tahmin katsayıları güncellendi.
// @author       FMP Assistant
// @match        https://footballmanagerproject.com/Team/Player*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=footballmanagerproject.com
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // --- DİL AYARLARI VE SÖZLÜK (HATA GİDERİLDİ: EN ÜSTE TAŞINDI) ---
    function detectLanguage() {
        const bodyText = document.body.innerText;
        // Türkçe kelimeler içeriyorsa TR, yoksa EN olarak varsayılır
        if (bodyText.includes("Gözlemci Raporları") || bodyText.includes("Yaş") || bodyText.includes("Kalite")) {
            return 'tr';
        }
        return 'en';
    }

    const currentLang = detectLanguage();
    const t = {
        tr: {
            btnText: "📊 AKILLI ANALİZ", reportTitle: "AKILLI OYUNCU ANALİZİ", calcPot: "HESAPLANAN POTANSİYEL",
            position: "Pozisyon", currQuality: "Mevcut Kalite", development: "Gelişim",
            professionalism: "Profesyonellik", sourceAI: "🤖 Yapay Zeka Tahmini", sourceReal: "✅ Gerçek Gözlemci Raporu",
            catEstimated: "Tahmini Veri", catReal: "Kesin Veri", unknown: "Bilinmiyor",
            proHigh: "Bilinmiyor (Gençse Yüksek)", bloomEarly: "Erken Patlama İhtimali", bloomNormal: "Normal (19-21)",
            bloomLate: "Geç Açılabilir", disclaimer: "* Tahmin, oyunun 4 ayrı potansiyel kategorisine (Fiziksel, Defans, Orta Saha, Hücum) ve gizli Profesyonellik/Liderlik niteliklerine erişilemediği için yaklaşık bir değerdir.",
            close: "KAPAT", error: "Analiz sırasında hata:", scoutFound: "Gerçek gözlemci raporu bulundu.",
            scoutNotFound: "Rapor yok, Akıllı Tahmin Modu devrede."
        },
        en: {
            btnText: "📊 SMART ANALYSIS", reportTitle: "SMART PLAYER ANALYSIS", calcPot: "CALCULATED POTENTIAL",
            position: "Position", currQuality: "Current Quality", development: "Blooming",
            professionalism: "Professionalism", sourceAI: "🤖 AI Prediction", sourceReal: "✅ Real Scout Report",
            catEstimated: "Estimated Data", catReal: "Confirmed Data", unknown: "Unknown",
            proHigh: "Unknown (High if young)", bloomEarly: "Early Blooming Likely", bloomNormal: "Normal (19-21)",
            bloomLate: "Late Bloomer", disclaimer: "* The prediction is an approximation because the game's 4 separate potential categories (Physical, Defense, Midfield, Attack) and hidden Professionalism/Leadership attributes are inaccessible.",
            close: "CLOSE", error: "Error during analysis:", scoutFound: "Real scout report found.",
            scoutNotFound: "No report, switching to Smart Prediction Mode."
        }
    }[currentLang];


    // --- BUTON VE TEMEL İŞLEVSELLİK ---
    const analyzeBtn = document.createElement("button");
    analyzeBtn.innerText = t.btnText; // BURADA ARTIK HATA VERMEYECEK
    analyzeBtn.id = "fmpAnalyzeBtn";
    Object.assign(analyzeBtn.style, {
        position: "fixed", top: "130px", right: "20px", zIndex: "9999",
        padding: "10px 20px", backgroundColor: "#2c3e50", color: "#00ff00",
        border: "2px solid #00ff00", borderRadius: "5px", cursor: "pointer",
        fontWeight: "bold", boxShadow: "0px 0px 15px rgba(0,255,0,0.3)"
    });

    document.body.appendChild(analyzeBtn);

    analyzeBtn.addEventListener("click", function() {
        try {
            const playerInfo = getPlayerInfo();
            let resultData;

            if (hasRealData()) {
                resultData = extractRealDataFromPage(playerInfo);
            } else {
                resultData = calculateSmartPrediction(playerInfo);
            }

            createEnhancedReport(playerInfo, resultData);
        } catch (error) {
            console.error(t.error, error);
            alert(t.error + " " + error.message);
        }
    });

    // --- VERİ ÇEKME ---
    function getPlayerInfo() {
        const info = { name: "Unknown Player", age: 20, quality: 0, club: "Unknown", position: "MR", isGK: false, isScouted: false };
        const nameEl = document.querySelector('h3');
        if (nameEl) info.name = nameEl.innerText.split('.')[1]?.trim() || nameEl.innerText;
        const bodyText = document.body.innerText;

        // Yaş tespiti
        const ageMatch = bodyText.match(/(?:Yaş|Age)[:\s]*(\d+[.,]\d+)/i);
        if (ageMatch) info.age = parseFloat(ageMatch[1].replace(',', '.'));

        // Kalite tespiti
        const qualityMatch = bodyText.match(/(?:Kalite|Quality|Rating)[^\d]*(\d+[.,]?\d*)/i);
        if (qualityMatch) info.quality = parseFloat(qualityMatch[1].replace(',', '.'));

        const clubMatch = bodyText.match(/(?:Kulüp|Club)\s*([^\n\r]+)/i);
        if (clubMatch) info.club = clubMatch[1].trim();

        // Pozisyon tespiti
        const posMatch = bodyText.match(/FPa\s+([A-Z]{2,3})/);
        if (posMatch) {
            info.position = posMatch[1];
            if (['KL', 'GK', 'KAL'].includes(info.position)) info.isGK = true;
        }

        const noReportTR = "Hazırlanmış bir rapor yok";
        info.isScouted = !(bodyText.includes(noReportTR) || bodyText.includes("No reports"));

        return info;
    }

    function hasRealData() {
        // Gerçek raporun varlığını kontrol eden kritik element
        return document.body.innerText.includes("/25") && document.querySelector('.rec');
    }

    // --- ÖNEMLİ GÜNCELLEME: AKILLI TAHMİN ALGORİTMASI (v7.0 Revize) ---
    function calculateSmartPrediction(info) {
        let growthBonus = 0;
        const age = info.age;
        const quality = info.quality;

        // Yaş 16.00 için ageFactor=0.0
        let ageFactor = age - 16;

        if (age < 16) {
            // 16 yaş altı
            growthBonus = 11.5 - ((age - 15) * 2.0);
        } else if (age < 19) {
            // 16-19 yaş: Kaliteye bağlı koşullu katsayılar uygulanır.
            let baseBonus;
            let agePenaltyFactor;

            if (quality < 10.0) {
                // Q çok düşük
                baseBonus = 11.5;
                agePenaltyFactor = 1.2;
            } else if (quality < 13.0) {
                // V7.0 Revize: Orta Kalitede bonus hafifçe artırıldı (7.5 -> 7.8)
                baseBonus = 7.8;
                agePenaltyFactor = 0.7;
            } else {
                // V7.0 Revize: Yüksek Kalitede (Q>=13.0) bonus agresifçe artırıldı (4.0 -> 6.5)
                baseBonus = 6.5;
                agePenaltyFactor = 0.3;
            }

            growthBonus = baseBonus - (ageFactor * agePenaltyFactor);

        } else if (age < 22) {
            // 19-22 yaş
            growthBonus = 1.8 - ((age - 19) * 0.4);
        } else if (age < 25) {
            // 22-24 yaş
            growthBonus = 2.0 - ((age - 22) * 0.3);
        } else {
            // 25+ yaş
            growthBonus = 1.0;
        }

        if (info.isGK) growthBonus *= 0.95;

        let predictedPotential = quality + growthBonus;
        predictedPotential = Math.min(25, predictedPotential);
        predictedPotential = Math.max(quality, predictedPotential);

        return {
            source: t.sourceAI, potential: predictedPotential.toFixed(1), category: t.catEstimated,
            hidden: { pro: t.proHigh, lead: t.unknown, blooming: calculateBloomingProb(age) }
        };
    }

    function calculateBloomingProb(age) {
        if(age <= 17) return t.bloomEarly;
        if(age <= 21) return t.bloomNormal;
        return t.bloomLate;
    }

    function extractRealDataFromPage(info) {
        let potential = 0;
        const potElement = document.querySelector('.rec');
        if (potElement) potential = potElement.innerText;

        const bodyText = document.body.innerText;
        let pro = t.unknown;

        const lines = bodyText.split('\n');
        lines.forEach(line => {
            if((line.includes("Profesyonellik") || line.includes("Professionalism")) && line.includes("/")) {
                // Gözlemci raporu ile gelen profesyonellik verisini çeker (örn: 8/8)
                pro = line.split(':')[1].trim();
            }
        });

        return {
            source: t.sourceReal, potential: potential, category: t.catReal,
            // Gerçek verilerde blooming ve liderlik raporun kendisinde değil, scout skill'ine bağlı gösterilir.
            hidden: { pro: pro, lead: "Mevcut/Available", blooming: "Mevcut/Available" }
        };
    }

    // --- RAPOR GÖRÜNTÜLEME VE SÜRÜKLEME ---
    function createEnhancedReport(info, data) {
        const oldBox = document.getElementById("fmpReportBox");
        if (oldBox) oldBox.remove();

        const box = document.createElement("div");
        box.id = "fmpReportBox";

        const potVal = parseFloat(data.potential);
        let color = "#ff4444";
        if(potVal > 15) color = "#ffff00";
        if(potVal > 20) color = "#00ff00";

        box.innerHTML = `
            <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: rgba(16, 20, 16, 0.95); color: white; border: 2px solid ${color}; border-radius: 10px; padding: 0; min-width: 400px; max-width: 90vw; box-shadow: 0 0 10px rgba(0,255,0,0.5);">
                <div id="reportHeader" style="background: ${color}; color: black; padding: 10px; font-weight: bold; border-radius: 8px 8px 0 0; display:flex; justify-content:space-between; cursor: move;">
                    <span>${info.name} (${info.age}y) - ${t.reportTitle}</span>
                    <span style="font-size: 11px; background: rgba(0,0,0,0.2); padding: 2px 6px; border-radius: 4px;">${data.source}</span>
                </div>

                <div style="padding: 20px;">
                    <div style="text-align: center; margin-bottom: 20px;">
                        <div style="font-size: 12px; color: #aaa; margin-bottom: 5px;">${t.calcPot}</div>
                        <div style="font-size: 48px; font-weight: bold; color: ${color}; text-shadow: 0 0 10px ${color};">
                            ${data.potential} <span style="font-size: 20px; color: #888;">/ 25</span>
                        </div>
                    </div>

                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; font-size: 13px; color: #ddd; background: rgba(255,255,255,0.05); padding: 10px; border-radius: 5px;">
                        <div>⚡ ${t.position}: <b style="color:white">${info.position}</b></div>
                        <div>⭐ ${t.currQuality}: <b style="color:white">${info.quality}</b></div>
                        <div>📈 ${t.development}: <b style="color:${color}">${data.hidden.blooming}</b></div>
                        <div>🧠 ${t.professionalism}: <b style="color:white">${data.hidden.pro}</b></div>
                    </div>

                    ${!info.isScouted ? `
                    <div style="margin-top: 15px; font-size: 11px; color: #888; text-align: center; border-top: 1px solid #333; padding-top: 10px;">
                        <i>${t.disclaimer}</i>
                    </div>
                    ` : ''}

                    <button id="closeFmpRep" style="width: 100%; margin-top: 15px; padding: 8px; background: #333; color: white; border: none; cursor: pointer; border-radius: 4px;">${t.close}</button>
                </div>
            </div>
        `;

        Object.assign(box.style, {
            position: "fixed", top: "15%", left: "50%", transform: "translate(-50%, 0)", zIndex: "10000"
        });

        document.body.appendChild(box);
        document.getElementById("closeFmpRep").onclick = () => box.remove();

        dragElement(box);
    }

    // Sürükle ve Bırak Fonksiyonu (V6.0'dan beri değişmedi)
    function dragElement(elmnt) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        const header = document.getElementById("reportHeader");

        if (header) {
            header.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;

            const newTop = elmnt.offsetTop - pos2;
            const newLeft = elmnt.offsetLeft - pos1;

            const offsetHeight = elmnt.offsetHeight;
            const offsetWidth = elmnt.offsetWidth;

            if (newTop > 0 && newTop < window.innerHeight - offsetHeight) {
                elmnt.style.top = newTop + "px";
            }
            if (newLeft > 0 && newLeft < window.innerWidth - offsetWidth) {
                elmnt.style.left = newLeft + "px";
            }

            elmnt.style.transform = "none";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

})();