CLUB RATING TM

Trophymanager: show average skill & value of first team (11 players) in last match.

// ==UserScript==
// @name         CLUB RATING TM
// @namespace    https://trophymanager.com
// @version      1
// @description  Trophymanager: show average skill & value of first team (11 players) in last match.
// @match        https://trophymanager.com/league/*
// @grant        none
// ==/UserScript==

(function () {
	'use strict';
const APPLICATION_PARAM = {
		DEFAULT_SHOW_MODE: "10",
		LOCAL_STORAGE_KEY: "TMVN_LEAGUE_LINEUP_SHOW_MODE",
		SHOW_MODE_ARR: ["11", "10", "01"]
	}

	const APP_COLOR = {
		LEVEL_1: "Darkred",
        LEVEL_2: "Orange",
		LEVEL_3: "Yellow",
		LEVEL_4: "Aqua",
		LEVEL_5: "White",
		LEVEL_6: "Blue",
		LEVEL_7: "Purple"
	};

	const BP_CLASS = {
		LEVEL_1: 150000000,
		LEVEL_2: 100000000,
		LEVEL_3: 80000000,
		LEVEL_4: 60000000,
		LEVEL_5: 40000000,
		LEVEL_6: 20000000,
		LEVEL_7: 0
	};

	const WA_CLASS = {
		LEVEL_1: 6000000,
		LEVEL_2: 5000000,
		LEVEL_3: 4000000,
		LEVEL_4: 3000000,
		LEVEL_5: 2000000,
		LEVEL_6: 1000000,
		LEVEL_7: 0
	};

	const XP_CLASS = {
		LEVEL_1: 55,
		LEVEL_2: 49,
		LEVEL_3: 44,
		LEVEL_4: 39,
		LEVEL_5: 32,
		LEVEL_6: 28,
		LEVEL_7: 25
	};

	const REC_CLASS = {
		LEVEL_1: 5.4,
		LEVEL_2: 5.2,
		LEVEL_3: 5.0,
		LEVEL_4: 4.8,
		LEVEL_5: 4.5,
		LEVEL_6: 4.2,
		LEVEL_7: 4
	};

	const R5_CLASS = {
		LEVEL_1: 109,
		LEVEL_2: 107,
		LEVEL_3: 105,
		LEVEL_4: 102,
		LEVEL_5: 100,
		LEVEL_6: 95,
		LEVEL_7: 80
	};

	const share_bonus = 0.25;
	const routine_cap = 40.0;

	try {
		$('.banner_placeholder.rectangle')[0].parentNode.removeChild($('.banner_placeholder.rectangle')[0]);
	} catch (err) {}

	var matchIds = [];
	$('#last_round_table td').each(function () {
		let hrefVal = $(this).children('a').attr('href');
		if (hrefVal) {
			let matchID = hrefVal.substr(hrefVal.lastIndexOf('matches/') + 8, hrefVal.length - 10);
			matchIds.push(matchID);
		}
	});

	var positionMap = new Map();
	var routineMap = new Map();
	var clubDatas = new Map();
	matchIds.forEach(function (matchId) {
		let xhr = new XMLHttpRequest();
		let url = 'https://trophymanager.com/ajax/match.ajax.php?id=' + matchId;

		xhr.open('GET', url, true);
		xhr.send();
		xhr.onreadystatechange = function () {
			try {
				if (this.readyState == 4 && this.status == 200) {
					let data = JSON.parse(this.responseText);

					let homeClubId = data.club.home.id;
					let awayClubId = data.club.away.id;

					let homeLineup = data.lineup.home;
					let awayLineup = data.lineup.away;
					let homePlayerIds = Object.getOwnPropertyNames(homeLineup);
					let awayPlayerIds = Object.getOwnPropertyNames(awayLineup);

					let homeD = [];
					let homeM = [];
					let homeF = [];
					let awayD = [];
					let awayM = [];
					let awayF = [];

					homePlayerIds.forEach((playerId, index) => {
						let position = homeLineup[playerId].position;
						if (position.indexOf("sub") > -1)
							return;
						positionMap.set(playerId, position);
						routineMap.set(playerId, Number(homeLineup[playerId].routine));
						if (position == "gk" || position == "dl" || position == "dr" || position == "dc" || position == "dcl" || position == "dcr") {
							homeD.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(homeLineup[playerId].routine)
							});
						} else if (position == "dml" || position == "dmr" || position == "dmc" || position == "dmcl" || position == "dmcr" || position == "ml" || position == "mr" || position == "mc" || position == "mcl" || position == "mcr") {
							homeM.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(homeLineup[playerId].routine)
							});
						} else {
							homeF.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(homeLineup[playerId].routine)
							});
						}
					});

					awayPlayerIds.forEach((playerId, index) => {
						let position = awayLineup[playerId].position;
						if (position.indexOf("sub") > -1)
							return;
						positionMap.set(playerId, position);
						routineMap.set(playerId, Number(awayLineup[playerId].routine));
						if (position == "gk" || position == "dl" || position == "dr" || position == "dc" || position == "dcl" || position == "dcr") {
							awayD.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(awayLineup[playerId].routine)
							});
						} else if (position == "dml" || position == "dmr" || position == "dmc" || position == "dmcl" || position == "dmcr" || position == "ml" || position == "mr" || position == "mc" || position == "mcl" || position == "mcr") {
							awayM.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(awayLineup[playerId].routine)
							});
						} else {
							awayF.push({
								"ID": playerId,
								"ROLE": position,
								"ROU": Number(awayLineup[playerId].routine)
							});
						}
					});

					let line_size;
					line_size = homeD.length;
					if (line_size > 1) {
						homeD.sort(compareByRoutineAsc);
						var min = homeD[0].ROU;
						if (min < routine_cap) {
							var max = homeD[line_size - 1].ROU;
							var min2 = homeD[1].ROU;
							var bonus = max * share_bonus;
							var new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(homeD[0].ID, new_routine);
						}
					}
					line_size = homeM.length;
					if (line_size > 1) {
						homeM.sort(compareByRoutineAsc);
						min = homeM[0].ROU;
						if (min < routine_cap) {
							max = homeM[line_size - 1].ROU;
							min2 = homeM[1].ROU;
							bonus = max * share_bonus;
							new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(homeM[0].ID, new_routine);
						}
					}
					line_size = homeF.length;
					if (line_size > 1) {
						homeF.sort(compareByRoutineAsc);
						min = homeF[0].ROU;
						if (min < routine_cap) {
							max = homeF[line_size - 1].ROU;
							min2 = homeF[1].ROU;
							bonus = max * share_bonus;
							new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(homeF[0].ID, new_routine);
						}
					}
					line_size = awayD.length;
					if (line_size > 1) {
						awayD.sort(compareByRoutineAsc);
						min = awayD[0].ROU;
						if (min < routine_cap) {
							max = awayD[line_size - 1].ROU;
							min2 = awayD[1].ROU;
							bonus = max * share_bonus;
							new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(awayD[0].ID, new_routine);
						}
					}
					line_size = awayM.length;
					if (line_size > 1) {
						awayM.sort(compareByRoutineAsc);
						min = awayM[0].ROU;
						if (min < routine_cap) {
							max = awayM[line_size - 1].ROU;
							min2 = awayM[1].ROU;
							bonus = max * share_bonus;
							new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(awayM[0].ID, new_routine);
						}
					}
					line_size = awayF.length;
					if (line_size > 1) {
						awayF.sort(compareByRoutineAsc);
						min = awayF[0].ROU;
						if (min < routine_cap) {
							max = awayF[line_size - 1].ROU;
							min2 = awayF[1].ROU;
							bonus = max * share_bonus;
							new_routine = min + bonus;
							new_routine = (new_routine < min2 ? new_routine : min2);
							new_routine = (new_routine < routine_cap ? new_routine : routine_cap);
							new_routine = parseFloat(new_routine.toFixed(1));
							routineMap.set(awayF[0].ID, new_routine);
						}
					}

					statistic(homePlayerIds, homeLineup).then((clubStatistic) => {
						clubDatas.set(homeClubId, {
							"XP": clubStatistic.XP,
							"Age": clubStatistic.Age,
							"ASI": clubStatistic.ASI,
							"Wage": clubStatistic.Wage,
							"BP": clubStatistic.BP,
							"REC": clubStatistic.REC,
							"R5": clubStatistic.R5
						});
					}).catch((error) => {});

					statistic(awayPlayerIds, awayLineup).then((clubStatistic) => {
						clubDatas.set(awayClubId, {
							"XP": clubStatistic.XP,
							"Age": clubStatistic.Age,
							"ASI": clubStatistic.ASI,
							"Wage": clubStatistic.Wage,
							"BP": clubStatistic.BP,
							"REC": clubStatistic.REC,
							"R5": clubStatistic.R5
						});
					}).catch((error) => {});
				}
			} catch (e) {
				//exception with forfeit match
				clubDatas.set(Math.floor(Math.random() * 1000), {
					"XP": 0,
					"Age": 0,
					"ASI": 0,
					"Wage": 0,
					"BP": 0,
					"REC": 0,
					"R5": 0
				});
				clubDatas.set(Math.floor(Math.random() * 1000), {
					"XP": 0,
					"Age": 0,
					"ASI": 0,
					"Wage": 0,
					"BP": 0,
					"REC": 0,
					"R5": 0
				});
			}
		};
	});

	var clubMap = new Map();
	var myInterval = setInterval(append, 1000);

	function getPlayerData(playerId) {
		return new Promise((resolve, reject) => {
			$.post("/ajax/tooltip.ajax.php", {
				"player_id": playerId
			}).done((responseText) => {
				var data = JSON.parse(responseText);

				if (routineMap.has(playerId)) {
					data.player.routine = routineMap.get(playerId).toString();
				}
				if (positionMap.has(playerId)) {
					data.player.favposition = positionMap.get(playerId);
				}

				var rrValue = calculateRR(data.player);
				var rec;
				if (rrValue[0].length == 2) {
					rec = Number(rrValue[0][0]) >= Number(rrValue[0][1]) ? Number(rrValue[0][0]) : Number(rrValue[0][1]);
				} else {
					rec = Number(rrValue[0][0]);
				}
				var r5;
				if (rrValue[1].length == 2) {
					r5 = Number(rrValue[1][0]) >= Number(rrValue[1][1]) ? Number(rrValue[1][0]) : Number(rrValue[1][1]);
				} else {
					r5 = Number(rrValue[1][0]);
				}

				resolve({
					XP: Number(data.player.routine.split(',').join('')),
					Age: Number(data.player.age) * 12 + Number(data.player.months),
					ASI: Number(data.player.skill_index.split(',').join('')),
					Wage: Number(data.player.wage.replace("<span class='coin'>", "").replace("<\/span>", "").split(',').join('')),
					BP: BP.compute(Number(data.player.skill_index.split(',').join('')), Number(data.player.age), Number(data.player.months), data.player.fp),
					REC: rec,
					R5: r5
				});
			}).fail((error) => {
				reject(error);
			});
		});
	}

	let BP = {
		compute: function (asi, age, month, position) {
			let pow = Math.pow;
			if (position === "GK") {
				return Math.round((asi * 500 * pow((300 / (age * 12 + month)), 2.5)) * 0.75);
			} else {
				return Math.round(asi * 500 * pow((300 / (age * 12 + month)), 2.5));
			}
		}
	};

	function statistic(playerIds, lineup) {
		return new Promise((resolve, reject) => {
			let clubStatistic = {
				XP: 0,
				Age: 0,
				ASI: 0,
				Wage: 0,
				BP: 0,
				REC: 0,
				R5: 0
			};
			let countLoop = 0;
			let countAjaxCall = 0;
			let countAjaxAnswer = 0;

			playerIds.forEach((playerId, index) => {
				if (lineup[playerId].position.indexOf("sub") < 0) {
					countAjaxCall++;
					countLoop++; //guarantee plus ajaxcall before
					getPlayerData(playerId).then((player) => {
						clubStatistic.XP += player.XP;
						clubStatistic.Age += player.Age;
						clubStatistic.ASI += player.ASI;
						clubStatistic.Wage += player.Wage;
						clubStatistic.BP += player.BP;
						clubStatistic.REC += player.REC;
						clubStatistic.R5 += player.R5;
						countAjaxAnswer++;
					}).catch((error) => {});
				} else {
					countLoop++
				}
			});

			function check() {
				if (!(countLoop == playerIds.length && countAjaxCall == countAjaxAnswer)) {
					setTimeout(check, 100);
				} else {
					resolve(clubStatistic);
				};
			}

			check();
		});
	}

	function append() {
		if (clubDatas.size < 18) {
			return;
		}
		clearInterval(myInterval);
		$('#overall_table td').each(function () {
			let clubId = $(this).children('a').attr('club_link');
			if (clubId) {
				let clubName = $(this).children('a')[0].innerHTML;
				clubMap.set(clubId, clubName);
			}
		});

		let firstSquadSkill =
			"<div class=\"box\">" +
			"<div class=\"box_head\">" +
			"<h2 class=\"std\">TROPHY MANAGER</h2>" +
			"</div>" +
			"<div class=\"box_body\">" +
			"<div class=\"box_shadow\"></div>" +
			"<span style='display: inline-block;'><input id='tm_script_league_lineup_input_show_mode' type='text' class='embossed' style='min-width: 100px;color :darkred; line-height: 100%; padding: 3px 3px 4px 3px;' placeholder='Show Mode'></span>" +
			"<span id='tm_script_league_lineup_button_show_mode_set' class='button' style='margin-left: 3px;'><span class='button_border'>show mode</span></span>" +
			"<h3>RATING CLUB</h3>" +
			"<div id=\"firstSquadSkill_content\" class=\"content_menu\"></div>" +
			"<h3></h3>" +
			"<div id=\"firstSquadValue_content\" class=\"content_menu\"></div>" +
			"</div>" +
			"<div class=\"box_footer\">" +
			"<div></div>" +
			"</div>" +
			"</div>";
		$(".column3_a").append(firstSquadSkill);
		document.getElementById('tm_script_league_lineup_button_show_mode_set').addEventListener('click', (e) => {
			setShowMode();
		});
		let showMode = localStorage.getItem(APPLICATION_PARAM.LOCAL_STORAGE_KEY);
		if (showMode == null || showMode == "") {
			showMode = APPLICATION_PARAM.DEFAULT_SHOW_MODE;
		}
		$('#tm_script_league_lineup_input_show_mode').val(showMode);
		let invidualMode = showMode.split("");
		if (invidualMode[0] == "1") {
			showSkill();
		}
		if (invidualMode[1] == "1") {
			showValue();
		}
	}

	function showSkill() {
		let firstSquadSkill_content = "<table>" +
			"<tr><th>Club</th><th align='right'>REC</th><th align='right'>ROU</th><th align='right'>R6</th>";

		let rowCount = 0;
		clubMap.forEach((value, key) => {
			rowCount++;
			let classOdd = "";
			if ((rowCount % 2) == 1) {
				classOdd = "class='odd'";
			}
			if (clubDatas.has(key)) {
				let clubData = clubDatas.get(key);
				let recColor,
				xpColor,
				r5Color;
				if (clubData.REC / 11 >= REC_CLASS.LEVEL_1) {
					recColor = APP_COLOR.LEVEL_1;
				} else if (clubData.REC / 11 >= REC_CLASS.LEVEL_2) {
					recColor = APP_COLOR.LEVEL_2;
				} else if (clubData.REC / 11 >= REC_CLASS.LEVEL_3) {
					recColor = APP_COLOR.LEVEL_3;
				} else if (clubData.REC / 11 >= REC_CLASS.LEVEL_4) {
					recColor = APP_COLOR.LEVEL_4;
				} else if (clubData.REC / 11 >= REC_CLASS.LEVEL_5) {
					recColor = APP_COLOR.LEVEL_5;
				} else if (clubData.REC / 11 >= REC_CLASS.LEVEL_6) {
					recColor = APP_COLOR.LEVEL_6;
				} else {
					recColor = APP_COLOR.LEVEL_7;
				}

				if (clubData.XP / 11 >= XP_CLASS.LEVEL_1) {
					xpColor = APP_COLOR.LEVEL_1;
				} else if (clubData.XP / 11 >= XP_CLASS.LEVEL_2) {
					xpColor = APP_COLOR.LEVEL_2;
				} else if (clubData.XP / 11 >= XP_CLASS.LEVEL_3) {
					xpColor = APP_COLOR.LEVEL_3;
				} else if (clubData.XP / 11 >= XP_CLASS.LEVEL_4) {
					xpColor = APP_COLOR.LEVEL_4;
				} else if (clubData.XP / 11 >= XP_CLASS.LEVEL_5) {
					xpColor = APP_COLOR.LEVEL_5;
				} else if (clubData.XP / 11 >= XP_CLASS.LEVEL_6) {
					xpColor = APP_COLOR.LEVEL_6;
				} else {
					xpColor = APP_COLOR.LEVEL_7;
				}

				if (clubData.R5 / 11 >= R5_CLASS.LEVEL_1) {
					r5Color = APP_COLOR.LEVEL_1;
				} else if (clubData.R5 / 11 >= R5_CLASS.LEVEL_2) {
					r5Color = APP_COLOR.LEVEL_2;
				} else if (clubData.R5 / 11 >= R5_CLASS.LEVEL_3) {
					r5Color = APP_COLOR.LEVEL_3;
				} else if (clubData.R5 / 11 >= R5_CLASS.LEVEL_4) {
					r5Color = APP_COLOR.LEVEL_4;
				} else if (clubData.R5 / 11 >= R5_CLASS.LEVEL_5) {
					r5Color = APP_COLOR.LEVEL_5;
				} else if (clubData.R5 / 11 >= R5_CLASS.LEVEL_6) {
					r5Color = APP_COLOR.LEVEL_6;
				} else {
					r5Color = APP_COLOR.LEVEL_7;
				}

				firstSquadSkill_content += "<tr " + classOdd + "><td>" + value + "</td><td align='right' style='color: " + recColor + ";'>" +
				(clubData.REC / 11).toFixed(4) +
				"</td><td align='right' style='color: " + xpColor + ";'>" +
				(clubData.XP / 11).toFixed(1) +
				"</td><td align='right' style='color: " + r5Color + ";'>" +
				(clubData.R5 / 11).toFixed(2) +
				"</td></tr>";
			} else {
				firstSquadSkill_content += "<tr " + classOdd + "><td>" + value + "</td><td></td><td></td><td></td></tr>";
			}

		});
		firstSquadSkill_content += "</table>";
		$("#firstSquadSkill_content").append(firstSquadSkill_content);
	}

	function showValue() {
		let firstSquadValue_content = "<table>" +
			"<tr><th>Club</th><th align='right'>BP(K)</th><th align='right'>Age</th><th align='right'>WA(K)</th></tr>";

		let rowCount = 0;
		clubMap.forEach((value, key) => {
			rowCount++;
			let classOdd = "";
			if ((rowCount % 2) == 1) {
				classOdd = "class='odd'";
			}
			if (clubDatas.has(key)) {
				let clubData = clubDatas.get(key);
				var bpColor,
				waColor;
				if (clubData.BP / 11 >= BP_CLASS.LEVEL_1) {
					bpColor = APP_COLOR.LEVEL_1;
				} else if (clubData.BP / 11 >= BP_CLASS.LEVEL_2) {
					bpColor = APP_COLOR.LEVEL_2;
				} else if (clubData.BP / 11 >= BP_CLASS.LEVEL_3) {
					bpColor = APP_COLOR.LEVEL_3;
				} else if (clubData.BP / 11 >= BP_CLASS.LEVEL_4) {
					bpColor = APP_COLOR.LEVEL_4;
				} else if (clubData.BP / 11 >= BP_CLASS.LEVEL_5) {
					bpColor = APP_COLOR.LEVEL_5;
				} else if (clubData.BP / 11 >= BP_CLASS.LEVEL_6) {
					bpColor = APP_COLOR.LEVEL_6;
				} else {
					bpColor = APP_COLOR.LEVEL_7;
				}

				if (clubData.Wage / 11 >= WA_CLASS.LEVEL_1) {
					waColor = APP_COLOR.LEVEL_1;
				} else if (clubData.Wage / 11 >= WA_CLASS.LEVEL_2) {
					waColor = APP_COLOR.LEVEL_2;
				} else if (clubData.Wage / 11 >= WA_CLASS.LEVEL_3) {
					waColor = APP_COLOR.LEVEL_3;
				} else if (clubData.Wage / 11 >= WA_CLASS.LEVEL_4) {
					waColor = APP_COLOR.LEVEL_4;
				} else if (clubData.Wage / 11 >= WA_CLASS.LEVEL_5) {
					waColor = APP_COLOR.LEVEL_5;
				} else if (clubData.Wage / 11 >= WA_CLASS.LEVEL_6) {
					waColor = APP_COLOR.LEVEL_6;
				} else {
					waColor = APP_COLOR.LEVEL_7;
				}

				firstSquadValue_content += "<tr " + classOdd + "><td>" + value + "</td><td align='right' style='color: " + bpColor + ";'>" +
				(clubData.BP / 11 / 1000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
				"</td><td align='right'>" +
				(clubData.Age / 11 / 12).toFixed(1) +
				"</td><td align='right' style='color: " + waColor + ";'>" +
				(clubData.Wage / 11 / 1000).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
				"</td></tr>";
			} else {
				firstSquadValue_content += "<tr " + classOdd + "><td>" + value + "</td><td></td><td></td><td></td></tr>";
			}

		});

		firstSquadValue_content += "</table>";

		$("#firstSquadValue_content").append(firstSquadValue_content);
	}

	function setShowMode() {
		let showMode = $('#tm_script_league_lineup_input_show_mode')[0].value;
		if (showMode == '') {
			localStorage.removeItem(APPLICATION_PARAM.LOCAL_STORAGE_KEY);
		} else if (!APPLICATION_PARAM.SHOW_MODE_ARR.includes(showMode)) {
			alert('Allowable show mode values: ' + APPLICATION_PARAM.SHOW_MODE_ARR);
		} else {
			localStorage.setItem(APPLICATION_PARAM.LOCAL_STORAGE_KEY, showMode);
			alert('Set successful, please refresh');
		}
	}

	// R5 weights
	//		Str				Sta				Pac				Mar				Tac				Wor				Pos				Pas				Cro				Tec				Hea				Fin				Lon				Set
	var weightR5 = [[0.5375, 0.00, 0.5925, 0.9500, 0.9206, 0.5274, 0.5825, 0.1313, 0.0656, 0.0937, 0.5282, 0.0491, 0.0216, 0.00], // DC
    [0.5140, 0.00, 0.6825, 0.8280, 0.8063, 0.5026, 0.5825, 0.1313, 0.2337, 0.1752, 0.4762, 0.0491, 0.0216, 0.00], // DL/R
    [0.4520, 0.00, 0.5683, 0.6864, 0.6727, 0.5780, 0.5720, 0.5105, 0.1095, 0.3504, 0.2850, 0.1050, 0.1102, 0.00], // DMC
    [0.4523, 0.00, 0.6666, 0.5765, 0.5499, 0.5327, 0.5120, 0.3255, 0.2949, 0.3226, 0.4547, 0.2230, 0.0893, 0.00], // DML/R
    [0.3291, 0.00, 0.4548, 0.3515, 0.3236, 0.5648, 0.5907, 0.6467, 0.0952, 0.6042, 0.2850, 0.5001, 0.2543, 0.00], // MC
    [0.2958, 0.00, 0.6709, 0.2840, 0.3039, 0.5042, 0.5420, 0.4126, 0.4244, 0.6020, 0.2580, 0.4501, 0.2521, 0.00], // ML/R
    [0.3363, 0.00, 0.4932, 0.2035, 0.1910, 0.5619, 0.5719, 0.6670, 0.0675, 0.6016, 0.4225, 0.6053, 0.2783, 0.00], // OMC
    [0.3585, 0.00, 0.6621, 0.1105, 0.1025, 0.5359, 0.5192, 0.3313, 0.4250, 0.6258, 0.4212, 0.6000, 0.3080, 0.00], // OML/R
    [0.4225, 0.00, 0.4500, 0.0003, 0.0002, 0.3845, 0.5015, 0.4050, 0.0010, 0.5825, 0.7000, 0.9500, 0.6025, 0.00], // F
    [0.35, 0.00, 0.35, 1.0, 0.6, 1.0, 0.5, 0.6, 0.3, 0.0, 0.3]]; // GK

	// RECb weights		Str				Sta				Pac				Mar				Tac				Wor				Pos				Pas				Cro				Tec				Hea				Fin				Lon				Set
	var weightRb = [[0.10493615, 0.05208547, 0.07934211, 0.14448971, 0.13159554, 0.06553072, 0.07778375, 0.06669303, 0.05158306, 0.02753168, 0.12055170, 0.01350989, 0.02549169, 0.03887550], // DC
		[0.07715535, 0.04943315, 0.11627229, 0.11638685, 0.12893778, 0.07747251, 0.06370799, 0.03830611, 0.10361093, 0.06253997, 0.09128094, 0.01314110, 0.02449199, 0.03726305], // DL/R
		[0.08219824, 0.08668831, 0.07434242, 0.09661001, 0.08894242, 0.08998026, 0.09281287, 0.08868309, 0.04753574, 0.06042619, 0.05396986, 0.05059984, 0.05660203, 0.03060871], // DMC
		[0.06744248, 0.06641401, 0.09977251, 0.08253749, 0.09709316, 0.09241026, 0.08513703, 0.06127851, 0.10275520, 0.07985941, 0.04618960, 0.03927270, 0.05285911, 0.02697852], // DML/R
		[0.07304213, 0.08174111, 0.07248656, 0.08482334, 0.07078726, 0.09568392, 0.09464529, 0.09580381, 0.04746231, 0.07093008, 0.04595281, 0.05955544, 0.07161249, 0.03547345], // MC
		[0.06527363, 0.06410270, 0.09701305, 0.07406706, 0.08563595, 0.09648566, 0.08651209, 0.06357183, 0.10819222, 0.07386495, 0.03245554, 0.05430668, 0.06572005, 0.03279859], // ML/R
		[0.07842736, 0.07744888, 0.07201150, 0.06734457, 0.05002348, 0.08350204, 0.08207655, 0.11181914, 0.03756112, 0.07486004, 0.06533972, 0.07457344, 0.09781475, 0.02719742], // OMC
		[0.06545375, 0.06145378, 0.10503536, 0.06421508, 0.07627526, 0.09232981, 0.07763931, 0.07001035, 0.11307331, 0.07298351, 0.04248486, 0.06462713, 0.07038293, 0.02403557], // OML/R
		[0.07738289, 0.05022488, 0.07790481, 0.01356516, 0.01038191, 0.06495444, 0.07721954, 0.07701905, 0.02680715, 0.07759692, 0.12701687, 0.15378395, 0.12808992, 0.03805251], // F
		[0.07466384, 0.07466384, 0.07466384, 0.14932769, 0.10452938, 0.14932769, 0.10452938, 0.10344411, 0.07512610, 0.04492581, 0.04479831]]; // GK

	var posNames = ["DC", "DCL", "DCR", "DL", "DR", "DMC", "DMCL", "DMCR", "DML", "DMR", "MC", "MCL", "MCR", "ML", "MR", "OMC", "OMCL", "OMCR", "OML", "OMR", "F", "FC", "FCL", "FCR", "GK"];
	var pos = [0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9];

	function funFix1(i) {
		i = (Math.round(i * 10) / 10).toFixed(1);
		return i;
	}

	function funFix2(i) {
		i = (Math.round(i * 100) / 100).toFixed(2);
		return i;
	}

	function funFix3(i) {
		i = (Math.round(i * 1000) / 1000).toFixed(3);
		return i;
	}

	function calculate(weightRb, weightR5, skills, posGain, posKeep, fp, rou, remainder, allBonus) {
		var rec = 0; // RERECb
		var ratingR = 0; // RatingR5
		var ratingR5 = 0; // RatingR5 + routine
		var ratingR5Bonus = 0; // RatingR5 + routine + bonus
		var remainderWeight = 0; // REREC remainder weight sum
		var remainderWeight2 = 0; // RatingR5 remainder weight sum
		var not20 = 0; // 20以外のスキル数
		for (var i = 0; i < weightRb[fp].length; i++) { // weightR[fp].length = n.pesi[pos] cioè le skill: 14 o 11
			rec += skills[i] * weightRb[fp][i];
			ratingR += skills[i] * weightR5[fp][i];
			if (skills[i] != 20) {
				remainderWeight += weightRb[fp][i];
				remainderWeight2 += weightR5[fp][i];
				not20++;
			}
		}
		if (remainder / not20 > 0.9 || not20 == 0) {
			if (fp == 9)
				not20 = 11;
			else
				not20 = 14;
			remainderWeight = 1;
			remainderWeight2 = 5;
		}
		rec = funFix3((rec + remainder * remainderWeight / not20 - 2) / 3);
		ratingR += remainder * remainderWeight2 / not20;
		ratingR5 = funFix2(ratingR * 1 + rou * 5);

		if (skills.length == 11) {
			ratingR5Bonus = funFix2(ratingR5 * 1 + allBonus * 1);
		} else {
			ratingR5Bonus = funFix2(ratingR5 * 1 + allBonus * 1 + posGain[fp] * 1 + posKeep[fp] * 1);
		}
		return [rec, ratingR5Bonus];
	}

	function calculateRR(current_player_info) {
		var skillArray = current_player_info.skills;
		var STR,
		STA,
		PAC,
		MAR,
		TAC,
		WOR,
		POS,
		PAS,
		CRO,
		TEC,
		HEA,
		FIN,
		LON,
		SET,
		HAN,
		ONE,
		REF,
		AER,
		JUM,
		COM,
		KIC,
		THR;
		var skillValue;
		for (var i = 0; i < skillArray.length; i++) {
			if (skillArray[i].key == 'null')
				continue;
			skillValue = skillArray[i].value;
			if (isNaN(skillValue)) {
				if (skillValue.indexOf('19') != -1) {
					skillValue = 19;
				} else if (skillValue.indexOf('20') != -1) {
					skillValue = 20;
				} else {
					throw 'Error skillValue: ' + skillValue;
				}
			}

			switch (skillArray[i].key) {
			case 'strength':
				STR = skillValue;
				break;
			case 'stamina':
				STA = skillValue;
				break;
			case 'pace':
				PAC = skillValue;
				break;
			case 'marking':
				MAR = skillValue;
				break;
			case 'tackling':
				TAC = skillValue;
				break;
			case 'workrate':
				WOR = skillValue;
				break;
			case 'positioning':
				POS = skillValue;
				break;
			case 'passing':
				PAS = skillValue;
				break;
			case 'crossing':
				CRO = skillValue;
				break;
			case 'technique':
				TEC = skillValue;
				break;
			case 'heading':
				HEA = skillValue;
				break;
			case 'finishing':
				FIN = skillValue;
				break;
			case 'longshots':
				LON = skillValue;
				break;
			case 'set_pieces':
				SET = skillValue;
				break;
			case 'handling':
				HAN = skillValue;
				break;
			case 'one_on_ones':
				ONE = skillValue;
				break;
			case 'reflexes':
				REF = skillValue;
				break;
			case 'aerial_ability':
				AER = skillValue;
				break;
			case 'jumping':
				JUM = skillValue;
				break;
			case 'communication':
				COM = skillValue;
				break;
			case 'kicking':
				KIC = skillValue;
				break;
			case 'throwing':
				THR = skillValue;
				break;
			default:
				throw 'Error skillArray[i].key: ' + skillArray[i].key;
			}
		}

		var ROLE = current_player_info.favposition.toUpperCase();
		var ROU = Number(current_player_info.routine.split(',').join(''));
		var ASI = Number(current_player_info.skill_index.split(',').join(''));

		var ROLE1,
		ROLE2;
		var role = ROLE.split(',');
		if (role.length == 2) {
			ROLE1 = role[0];
			ROLE2 = role[1];
		} else {
			ROLE1 = role[0];
			ROLE2 = -1;
		}

		var fp,
		fp2 = -1;
		for (var i = 0; i < posNames.length; i++) {
			if (posNames[i] == ROLE1)
				fp = pos[i];
			if (ROLE2 != -1 && posNames[i] == ROLE2)
				fp2 = pos[i];
		}
		if (fp == 9) {
			var weight = 48717927500;
			var skills = [STR, STA, PAC, HAN, ONE, REF, AER, JUM, COM, KIC, THR];
		} else {
			weight = 263533760000;
			skills = [STR, STA, PAC, MAR, TAC, WOR, POS, PAS, CRO, TEC, HEA, FIN, LON, SET];
		}

		var goldstar = 0;
		var skillSum = 0;
		var skillsB = [];
		for (i = 0; i < skills.length; i++) {
			skillSum += parseInt(skills[i]);
		}
		var remainder = Math.round((Math.pow(2, Math.log(weight * ASI) / Math.log(Math.pow(2, 7))) - skillSum) * 10) / 10; // RatingR5 remainder
		for (var j = 0; j < 2; j++) {
			for (i = 0; i < 14; i++) {
				if (j == 0 && skills[i] == 20)
					goldstar++;
				if (j == 1) {
					if (skills[i] != 20)
						skillsB[i] = skills[i] * 1 + remainder / (14 - goldstar);
					else
						skillsB[i] = skills[i];
				}
			}
		}

		var routine = (3 / 100) * (100 - (100) * Math.pow(Math.E, -ROU * 0.035));
		var strRou = skillsB[0] * 1 + routine;
		var staRou = skillsB[1] * 1;
		var pacRou = skillsB[2] * 1 + routine;
		var marRou = skillsB[3] * 1 + routine;
		var tacRou = skillsB[4] * 1 + routine;
		var worRou = skillsB[5] * 1 + routine;
		var posRou = skillsB[6] * 1 + routine;
		var pasRou = skillsB[7] * 1 + routine;
		var croRou = skillsB[8] * 1 + routine;
		var tecRou = skillsB[9] * 1 + routine;
		var heaRou = skillsB[10] * 1 + routine;
		var finRou = skillsB[11] * 1 + routine;
		var lonRou = skillsB[12] * 1 + routine;
		var setRou = skillsB[13] * 1 + routine;

		var headerBonus;
		if (heaRou > 12)
			headerBonus = funFix2((Math.pow(Math.E, (heaRou - 10) ** 3 / 1584.77) - 1) * 0.8 + Math.pow(Math.E, (strRou * strRou * 0.007) / 8.73021) * 0.15 + Math.pow(Math.E, (posRou * posRou * 0.007) / 8.73021) * 0.05);
		else
			headerBonus = 0;

		var fkBonus = funFix2(Math.pow(Math.E, Math.pow(setRou + lonRou + tecRou * 0.5, 2) * 0.002) / 327.92526);
		var ckBonus = funFix2(Math.pow(Math.E, Math.pow(setRou + croRou + tecRou * 0.5, 2) * 0.002) / 983.65770);
		var pkBonus = funFix2(Math.pow(Math.E, Math.pow(setRou + finRou + tecRou * 0.5, 2) * 0.002) / 1967.31409);

		var allBonus = 0;
		if (skills.length == 11)
			allBonus = 0;
		else
			allBonus = headerBonus * 1 + fkBonus * 1 + ckBonus * 1 + pkBonus * 1;

		var gainBase = funFix2((strRou ** 2 + staRou ** 2 * 0.5 + pacRou ** 2 * 0.5 + marRou ** 2 + tacRou ** 2 + worRou ** 2 + posRou ** 2) / 6 / 22.9 ** 2);
		var keepBase = funFix2((strRou ** 2 * 0.5 + staRou ** 2 * 0.5 + pacRou ** 2 + marRou ** 2 + tacRou ** 2 + worRou ** 2 + posRou ** 2) / 6 / 22.9 ** 2);
		//	0:DC			1:DL/R			2:DMC			3:DML/R			4:MC			5:ML/R			6:OMC			7:OML/R			8:F
		var posGain = [gainBase * 0.3, gainBase * 0.3, gainBase * 0.9, gainBase * 0.6, gainBase * 1.5, gainBase * 0.9, gainBase * 0.9, gainBase * 0.6, gainBase * 0.3];
		var posKeep = [keepBase * 0.3, keepBase * 0.3, keepBase * 0.9, keepBase * 0.6, keepBase * 1.5, keepBase * 0.9, keepBase * 0.9, keepBase * 0.6, keepBase * 0.3];

		var valueFp = calculate(weightRb, weightR5, skills, posGain, posKeep, fp, routine, remainder, allBonus);
		var rec = [valueFp[0]];
		var r5 = [valueFp[1]];

		if (fp2 != -1 && fp2 != fp) {
			var valueFp2 = calculate(weightRb, weightR5, skills, posGain, posKeep, fp2, routine, remainder, allBonus);
			rec.push(valueFp2[0]);
			r5.push(valueFp2[1]);
		}

		return [rec, r5];
	}

	function compareByRoutineAsc(a, b) {
		var rou_a = parseFloat(a.ROU);
		var rou_b = parseFloat(b.ROU);
		return (rou_a - rou_b);
	}
})();

QingJ © 2025

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