Hata Düzeltmesi: T değişkeni hatası giderildi. Yüksek Potansiyel (RP) tahmin katsayıları güncellendi.
当前为
// ==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;
}
}
})();