ogame highscore improved

Some improvements to the highscore like a bar to switch between lists even if you are scrolled down.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name           ogame highscore improved
// @namespace      marshen
// @description    Some improvements to the highscore like a bar to switch between lists even if you are scrolled down.
// @include        http*://*.ogame.gameforge.com/game/index.php?page=highscore*
// @version        1.0.6.5
// ==/UserScript==


(function(){
	/* CONFIG */
	var language = "en";
	/* Dear translator, please don't upload a copy of this script but send me an email (which you can find on http://o-calc.com)!
	   Please use the german ("de") language as a template to translate.
	   The syntax is "key" : "value" where the translation goes into "value".
	   If a word has no translation you can remove that line. You can also remove the lines with 'false' as value.
	   Thank you.
	*/
	var localization = {
		"de" : {
			"thousand_seperator" : ".",
			"decimal_mark" : ",",
			"status_abbr_v" : "u",
			"No planets found for this player. It may take some time until the data is available by the OGame server." : "Keine Planeten gefunden für diesen Spieler. Bis die Daten vom OGame Server zur Verfügung gestellt werden, kann einige Zeit vergehen.",
			"Rankings" : "Rangliste",
			"Planets" : "Planeten",
			"Planet" : false,
			"Coordinate" : "Position",
			"Points: " : "Punkte: ",
			"Ships: " : "Schiffe: ",
			"Economy: " : "Ökonomie: ",
			"Real economy points.<br /><br />Points with defense: " : "Tatsächliche Ökonomie Punkte.<br /><br />Punkte inklusive Verteidigung: ",
			"Research: " : "Forschung: ",
			"Military: " : "Militär: ",
			"Real military points.<br /><br />Points with defense: " : "Tatsächliche Militär Punkte.<br /><br />Punkte inklusive Verteidigung: ",
			"Built: " : "Gebaut: ",
			"Destroyed: " : "Zerstört: ",
			"Lost: " : "Verloren: ",
			"Defense: " : "Verteidigung: ",
			"Honor: " : "Ehrenpunkte: "
		},
		"en" : {
			"thousand_seperator" : ",",
			"decimal_mark" : ".",
			"rank_sign" : "#",
			"percent_sign" : "%",
			"status_abbr_v" : "v",
			"status_abbr_i" : "i",
			"status_abbr_I" : "I",
			"status_abbr_o" : "o",
			"moon_abbr" : " M"
		},
        "ru" : {
			"thousand_seperator" : ".",
			"decimal_mark" : ",",
			"status_abbr_v" : "РО",
			"No planets found for this player. It may take some time until the data is available by the OGame server." : "Не найдено планет этого игрока. Это может занять некоторое время, пока не станут доступны данные с сервера OGame.",
			"Rankings" : "Статистика",
			"Planets" : "Планеты",
			"Planet" : false,
			"Coordinate" : "Координаты",
			"Points: " : "Очки: ",
			"Ships: " : "Корабли: ",
			"Economy: " : "Экономика: ",
			"Real economy points.<br /><br />Points with defense: " : "Фактические очки экономики.<br /><br />Очки вместе с обороной: ",
			"Research: " : "Исследования: ",
			"Military: " : "Вооружение: ",
			"Real military points.<br /><br />Points with defense: " : "Фактические очки вооружения.<br /><br />Очки вместе с обороной: ",
			"Built: " : "Построено: ",
			"Destroyed: " : "Уничтожено: ",
			"Lost: " : "Потеряно: ",
			"Defense: " : "Оборона: ",
			"Honor: " : "Очки чести: ",            
            "status_abbr_b" : "з",
		},       
	};
	
	var config = {
		barScrolling : true,
		showShips : true,
		extendedInformation : true,
		nextPrevPageLink : true,
		planetListSortCategory : 0, // 0: planet creation time, 1: planet names, 2: coordinates
		planetListSortAscending : true,
		status : {
			'v' : {
				className : 'status_abbr_vacation',
				value : 10
			},
			'o' : {
				className : 'status_abbr_outlaw',
				value : 1
			},
			'i' : {
				className : 'status_abbr_inactive',
				value : 2
			},
			'I' : {
				className : 'status_abbr_longinactive',
				value : 3
			}
		}
	};
	
	/* INIT */
	var data = {
		// Also contains the points of a player in this format:
		// <player_id> : {
		//   <statistic_type> : <array(int rank, int points)>
		//   "name" : <string fullname>
		//   "status" : <string>
		//   "planets" : <array(int number, string name, string coordinates, bool moon)>
		// }
		cache : {
			// Contains:
			// "universe" : <XML>
			// "players" : <XML>
			// Contains for each statistic type the last ajax response:
			// <statistic_type> : <XML>
		}
	};
	
	var TYPES = {
		GENERAL : 0,
		ECONOMY : 1,
		RESEARCH : 2,
		MILITARY : 3,
		MILITARY_POINTS_BUILT : 5,
		MILITARY_POINTS_DESTROYED : 6,
		MILITARY_POINTS_LOST : 4,
		HONOR : 7
	};

	/* INIT */
	var style;
	var version = document.getElementsByName('ogame-version');
	version = (version.length != 1 ? 0 : getVersion(version[0].getAttribute('content')));
	if (version < 30001 || !document.getElementsByClassName)
		return;
	if (config.barScrolling)
		document.addEventListener('scroll', scroll, false);
	if (version < 40100)
		config.extendedInformation = false;
		
	var lang = document.getElementsByName('ogame-language');
	if (lang.length > 0)
	{
		language = lang[0].getAttribute('content');
	}
	
	modifyPageBar();
	
	if (config.showShips || config.extendedInformation)
	{
		var content = document.getElementById('stat_list_content');
		content.addEventListener('DOMNodeInserted', nodeInserted, false);
	}
	
	if (config.barScrolling)
	{
		addStyle(
			'#highscore #send.improve #row { width: 630px; top: 0; position: fixed; background: #0D1014;  border-bottom: 10px solid #22313B; z-index: 9 }'
		);
		
		addStyle(
			'#highscore #send.improve #stat_list_content { padding-top: 65px; }'
		);
		
		addStyle(
			'#highscore #send.improve #stat_list_content .pagebar.hImproved_firstBar { width: 610px; top: 84px; position:fixed; background: #0d1014; z-index: 9 }'
		);
		
		// fix for 5.1
		addStyle(
			'#send.improve #highscoreHeadline { float: none; margin-top: 43px; }'
		);
		
		addStyle(
			'#send.improve #scrollToTop { z-index: 10; }'
		);
	}
	
	if (config.extendedInformation)
	{
		var ranks = document.getElementById('ranks');
		if (ranks)
		{
			addStyle(
				'.extendedInfoToggle { display: inline-block; width: 20px; height: 18px; margin-bottom: -4px; background: url("/cdn/img/navigation/message-open-close-bg.gif"); }'
			);
			
			addStyle(
				'.extendedInfoToggle:hover { background-position: -20px 0px; }'
			);
			
			addStyle(
				'.extendedInfoToggleExpanded { background-position: 0px -18px; }'
			);
			
			addStyle(
				'.extendedInfoToggleExpanded:hover { background-position: -20px -18px; }'
			);
			
			addStyle(
				'.hImproved_information > td { padding : 0 !important; }'
			);
			
			addStyle(
				'.hImproved_information .hImproved_information_head { background:url("/cdn/img/layout/header-stuff.gif") center; background-size: 100%; margin: 0px; height: 32px; padding: 0 15px 0 25px; }'
			);
			
			addStyle(
				'.hImproved_information .hImproved_playername { font-weight:bold; font-size: 11px; line-height: 32px; }'
			);
			
			addStyle(
				'.hImproved_information .hImproved_status { font-size: 9px }'
			);
			
			addStyle(
				'.hImproved_information ul.hImproved_select { float: right; }'
			);
			
			addStyle(
				'.hImproved_information ul.hImproved_select li { background:url("/cdn/img/navigation/network-tab-below-bg-short.gif"); display: inline-block; width: 150px; height: 23px; margin-top: 9px }'
			);
			
			addStyle(
				'.hImproved_information ul.hImproved_select a { width: 100%; display: inline-block; text-align: center; line-height: 23px; }'
			);
			
			// score table styles
			addStyle(
				'.hImproved_general { color: #D29D00; }'
			);
			addStyle(
				'.hImproved_economy { color: #848484; }'
			);
			addStyle(
				'.hImproved_research { color: #9C0; }'
			);
			addStyle(
				'.hImproved_military, .hImproved_military_built, .hImproved_military_destroyed, .hImproved_military_lost, .hImproved_ships { color: #D43635; }'
			);
			addStyle(
				'.hImproved_defense { color: #6F9FC8; }'
			);
			addStyle(
				'.hImproved_honor { color: #FF6; }'
			);
			
			addStyle(
				'.hImproved_general, .hImproved_economy, .hImproved_research, .hImproved_defense, .hImproved_emptyCell, .hImproved_even { background: #13181D }'
			);
			
			addStyle(
				'.hImproved_scores td { width: 50%; }'
			);
			addStyle(
				'#highscore #ranks .hImproved_tableHead td { font-weight: bold; text-align: left; border-bottom: 1px dotted #848484; }'
			);
			addStyle(
				'#highscore #ranks .hImproved_planets tBody tr:first-child td { border-top: 0; }'
			);
			addStyle(
				'#highscore .hImproved_planets .hImproved_coords a { color: white }'
			);
			addStyle(
				'.hImproved_planets .hImproved_planetnumber { width: 20px; text-align: right; }'
			);
			addStyle(
				'#highscore .contentbox div.content table.hImproved_scores, #highscore .contentbox div.content table.hImproved_planets { width: 580px; margin: 0 auto 10px; }'
			);
			addStyle(
				'.hImproved_home, #highscore .hImproved_planets .hImproved_home .hImproved_coords a { color: #6F9FC8; }'
			);
			addStyle(
				'#highscore a.hImproved_sortable { padding-left: 10px; background: no-repeat left url(data:image/gif;base64,R0lGODlhCQAFAJEAAAAAAP///4SEhP///yH5BAEAAAMALAAAAAAJAAUAAAILnCenworZTHx0iQIAOw==); }'
			);
			addStyle(
				'#highscore a.hImproved_sortable.hImproved_asc { background-image: url(\'http://gf1.geo.gfsrv.net/cdnf5/1c7545144452ec3e38c9fba216c4f9.gif\'); }'
			);
			addStyle(
				'#highscore a.hImproved_sortable.hImproved_desc { background-image: url(\'http://gf3.geo.gfsrv.net/cdn5e/7e6b4e65bec62ac2f10ea24ba76c51.gif\'); }'
			);
			
			addExtendedInformationToggles(ranks.tBodies[0]);
		}
	}
	
	/* UTILS */
	
	/**
	 * Parses a given version to an integer.
	 * @param	pVersion	The version string to parse.
	 * @return	The parsed version.
	 */
	function getVersion(pVersion)
	{
		var version = pVersion.toString().split('.');
		if (version.length >= 3)
		{
			// This is why I would like to see the version as a number because otherwise you can't compare it!
			var intversion = parseInt(version[0]) * 10000 + parseInt(version[1]) * 100 + parseInt(version[2]);
			return intversion;
		}
		return parseInt(pVersion);
	}
	
	// Adds a style rule.
	function addStyle(rule)
	{
		if (!style)
		{
			style = document.createElement('style');
			style.setAttribute('type', 'text/css')
			style.setAttribute('id', 'highscore_improved_style');
			
			var head = document.head || document.getElementsByTagName('head')[0];
			head.appendChild(style);
		}
		style.appendChild(document.createTextNode(rule + "\n"));
	}
	
	// Adds a class to an element.
	function addClass (elm, className) {
		if (elm.className.length == 0) {
			elm.className = className;
		} else {
			if (!hasClass(elm, className)) {
				elm.className += ' ' + className;
			}
		}
	}

	// Removes a class from an element.
	function removeClass (elm, className) {
		if (hasClass(elm, className))
		{
			var classes = elm.className.split(' ');
			for (var i = 0; i < classes.length; i++) {
				if (classes[i] == className) {
					classes.splice(i, 1);
				}
			}
			elm.className = classes.join(' ');
		}
	}
	
	// Has an element a class.
	function hasClass (elm, className) {
		return ((' ' + elm.className + ' ').indexOf(className) > -1);
	}
	
	function trim(s)
	{
		s = s.toString();
		if (s.trim)
		{
			return s.trim();
		}
		return s.replace(/^\s+/, '').replace(/\s+$/, '');
	}
	
	// Adds thousand seperator
	function addSeperator(s)
	{
		var seperator = L('thousand_seperator');
		var mark = L('decimal_mark');
	 
		s = s.toString();
		// Separate number and fraction.
		var a = s.split('.');
		var neg = (a[0][0] == '-' ? '-' : '');
		var num = a[0].substr(neg.length); // Number w/o negative sign.
		var frac = a[1];
		var res = '';
		var len = num.length;
		while (len > 3){
			res = seperator + num.substr(len - 3, 3) + res;
			len -= 3;
		}
		res = neg + num.substr(0, len) + res;
	 
		if (frac)
			res = res + mark + frac;
		return res;
	}
	
	// Get localization
	function L(key)
	{
		if (localization[language] && localization[language][key])
			return localization[language][key];
		if (localization['en'][key])
			return localization['en'][key];
		return key;
	}
	
	
	/* DATA HANDLING FUNCTIONS */
	function getHighscoreURL(type)
	{
		return location.protocol + "//" + location.host + '/api/highscore.xml?category=1&type=' + type;
	}
	
	function getUniverseURL()
	{
		return location.protocol + "//" + location.host + '/api/universe.xml';
	}
	
	function getPlayersURL()
	{
		return location.protocol + "//" + location.host + '/api/players.xml';
	}
	
	function getPlayerURL(id)
	{
		return location.protocol + "//" + location.host + '/api/playerData.xml?id=' + id;
	}
	
	function isDataComplete()
	{
		return (requests.length > 0 && currentRequest == requests.length);
	}
	
	function isPlayerDataComplete(playerId)
	{
		var player = data[playerId];
		return player != null;
	}
	
	function isValidType(type)
	{
		var tmp = parseInt(type);
		return !isNaN(tmp) && tmp >= 0 && tmp <= TYPES.HONOR;
	}
	
	function loadNextRequest()
	{
		// If there are still more requests in the queue load them.
		if (currentRequest < requests.length)
		{
			var http;
			if (window.XMLHttpRequest) {
				http = new XMLHttpRequest();
			} else if (window.ActiveXObject) {
				http = new ActiveXObject("Microsoft.XMLHTTP");
			}
			
			if (http != null) {
				var url;
				if (requests[currentRequest] == "universe")
				{
					url = getUniverseURL();
				}
				else if (requests[currentRequest] == "players")
				{
					url = getPlayersURL();
				}
				else
				{
					url = getHighscoreURL(requests[currentRequest]);
				}
				http.open("GET", url, true);
				http.onreadystatechange = function () {
					if (http.readyState == 4 && http.status == 200)
					{
						// Save the xml and start next request.
						data.cache[requests[currentRequest]] = http.responseXML;
						currentRequest++;
						loadNextRequest();
						
						var percent = Math.min(Math.round(currentRequest / requests.length * 100), 99);
						var spans = document.getElementsByName('hImproved_loading');
						for (var i = 0; i < spans.length; i++)
						{
							spans[i].firstChild.nodeValue = percent;
						}
					}
				}
				http.send(null);
			}
		}
		else
		{
			onDataComplete();
		}
	}
	
	
	//////////
	// Will be called when all AJAX requests have been finished. Build UI for the pending players.
	function onDataComplete()
	{
		for (var i = 0; i < pendingPlayers.length; i++)
		{
			showData(pendingPlayers[i][0], pendingPlayers[i][1]);
		}
	}
	
	var requests = [];
	var currentRequest = 0;
	var pendingPlayers = [];
	
	/////////////
	// Gather data and build UI for a player.
	function showData(playerId, container)
	{
		// If the data hasn't been loading enqueue the player for later.
		if (!isDataComplete())
		{
			pendingPlayers.push([playerId, container]);
			// When this is being called the first time start AJAX requests.
			if (requests.length == 0)
			{
				requests.push("universe");
				requests.push("players");
				for (var i in TYPES)
				{
					requests.push(TYPES[i]);
				}
				loadNextRequest();
			}
		}
		else
		{
			// XML has been received. Check if data has already been fetched.
			if (!isPlayerDataComplete(playerId))
			{
				// Fetch data from XML
				var playerData = {
					planets : []
				};
				// Fetch highscore data.
				for (var i in TYPES)
				{
					var players = data.cache[TYPES[i]].getElementsByTagName('player');
					var rank = 0;
					var score = 0;
					for (var j = 0; j < players.length; j++)
					{
						if (players[j].getAttribute('id') == playerId)
						{
							rank = parseInt(players[j].getAttribute('position'));
							score = parseInt(players[j].getAttribute('score'));
							playerData[TYPES[i]] = [rank, score];
							
							if (TYPES[i] == TYPES.MILITARY)
							{
								var ships = 0;
								if (players[j].getAttribute('ships'))
								{
									ships = parseInt(players[j].getAttribute('ships'));
								}
								playerData[TYPES[i]].push(ships);
							}
							break;
						}
					}
				}
				// Fetch player data.
				var players = data.cache['players'].getElementsByTagName('player');
				for (var i = 0; i < players.length; i++)
				{
					if (players[i].getAttribute('id') == playerId)
					{
						playerData['name'] = players[i].getAttribute('name');
						playerData['status'] = players[i].getAttribute('status');
						break;
					}
				}
				// Fetch planets.
				var planets = data.cache['universe'].getElementsByTagName('planet');
				for (var i = 0; i < planets.length; i++)
				{
					if (planets[i].getAttribute('player') == playerId)
					{
						var planet = planets[i];
						var name = planet.getAttribute('name');
						var moon = (planet.firstChild != null);
						var coords = planet.getAttribute('coords');
						playerData.planets.push([playerData.planets.length + 1, name, coords, moon]);
					}
				}
				
				data[playerId] = playerData;
				// Planets are sorted by number ascending. Sort if current sorting isn't number ascending
				if (config.planetListSortCategory != 0 || config.planetListSortAscending == false)
				{
					data[playerId].planets.sort(sortPlanetsComparison);
				}
			}
			// Build UI
			
			// Calculate data
			var scores = {
				general : data[playerId][TYPES.GENERAL],
				economy : data[playerId][TYPES.ECONOMY],
				economyActual : null,
				research : data[playerId][TYPES.RESEARCH],
				military : data[playerId][TYPES.MILITARY],
				militaryActual : null,
				military_built : data[playerId][TYPES.MILITARY_POINTS_BUILT],
				military_destroyed : data[playerId][TYPES.MILITARY_POINTS_DESTROYED],
				military_lost : data[playerId][TYPES.MILITARY_POINTS_LOST],
				honor : data[playerId][TYPES.HONOR],
				defenseActual : null,
			}
			
			scores.defenseActual = Math.max((scores.economy[1] + scores.research[1] + scores.military[1]) - scores.general[1], 0);
			scores.economyActual = Math.max(Math.floor(scores.economy[1] - scores.defenseActual), 0);
			scores.militaryActual = Math.max(Math.floor(scores.military[1] - scores.defenseActual), 0);
			
			scores.economyPercentage = scores.economyActual / scores.general[1];
			scores.researchPercentage = scores.research[1] / scores.general[1];
			scores.militaryPercentage = scores.militaryActual / scores.general[1];
			scores.defensePercentage = scores.defenseActual / scores.general[1];
			
			// Clear container.
			while (container.firstChild)
			{
				container.removeChild(container.firstChild);
			}
			
			// Fill UI
			var head = document.createElement('div');
			head.setAttribute('class', 'hImproved_information_head');
			var span = document.createElement('span');
			span.appendChild(document.createTextNode((data[playerId].name ? data[playerId].name : '')));
			span.setAttribute('class', 'hImproved_playername');
			head.appendChild(span);
			var status = data[playerId].status;
			
			if (status)
			{
				var commandingStatus;
				var text = '';
				span = document.createElement('span');
				for (var i = 0; i < status.length; i++)
				{
					if (!commandingStatus || commandingStatus.value < config.status[status[i]].value)
					{
						commandingStatus = config.status[status[i]];
					}
					text += L("status_abbr_" + status[i]);
				}
				span.appendChild(document.createTextNode(' (' + text + ')'));
				span.setAttribute('class', 'hImproved_status ' + commandingStatus.className);
				head.appendChild(span);
			}
			
			var list = document.createElement('ul');
			list.setAttribute('class', 'hImproved_select');
			var item = document.createElement('li');
			var link_scores = document.createElement('a');
			link_scores.appendChild(document.createTextNode(L("Rankings")));
			link_scores.setAttribute('href', 'javascript:void(0)');
			item.appendChild(link_scores);
			list.appendChild(item);
			
			item = document.createElement('li');
			var link_planets = document.createElement('a');
			link_planets.appendChild(document.createTextNode(L("Planets")));
			link_planets.setAttribute('href', 'javascript:void(0)');
			item.appendChild(link_planets);
			list.appendChild(item);
			
			head.appendChild(list);
			
			container.appendChild(head);
			
			
			
			// Scores table
			var scoreTable = document.createElement('table');
			scoreTable.setAttribute('class', 'hImproved_scores');
			var scoreTBody = document.createElement('tBody');
			scoreTable.appendChild(scoreTBody);
			for (var i = 0; i < 5; i++)
			{
				var row = document.createElement('tr');
				for (var j = 0; j < 2; j++)
				{
					var cell = document.createElement('td');
					row.appendChild(cell);
				}
				scoreTBody.appendChild(row);
			}
			container.appendChild(scoreTable);
			
			
			// General.
			fillScoresCell(scoreTBody.rows[0].cells[0], {
				desc : 'Points: ',
				score : scores.general[1],
				rank : scores.general[0],
				className : 'hImproved_general'
			});
			
			// Ships.
			fillScoresCell(scoreTBody.rows[0].cells[1], {
				desc : 'Ships: ',
				score : scores.military[2],
				className : 'hImproved_ships'
			});
			
			// Economy.
			fillScoresCell(scoreTBody.rows[1].cells[0], {
				desc : 'Economy: ',
				tooltip : ['Real economy points.<br /><br />Points with defense: ', addSeperator(scores.economy[1])],
				score : scores.economyActual,
				rank : scores.economy[0],
				percentage : scores.economyPercentage,
				className : 'hImproved_economy'
			});
			
			// Research.
			fillScoresCell(scoreTBody.rows[2].cells[0], {
				desc : 'Research: ',
				score : scores.research[1],
				rank : scores.research[0],
				percentage : scores.researchPercentage,
				className : 'hImproved_research'
			});
			
			// Military.
			fillScoresCell(scoreTBody.rows[3].cells[0], {
				desc : 'Military: ',
				tooltip : ['Real military points.<br /><br />Points with defense: ', addSeperator(scores.military[1])],
				score : scores.militaryActual,
				rank : scores.military[0],
				percentage : scores.militaryPercentage,
				className : 'hImproved_military'
			});
			
			// Military built.
			fillScoresCell(scoreTBody.rows[1].cells[1], {
				desc : 'Built: ',
				score : scores.military_built[1],
				rank : scores.military_built[0],
				className : 'hImproved_military_built'
			});
			
			// Military destroyed.
			fillScoresCell(scoreTBody.rows[2].cells[1], {
				desc : 'Destroyed: ',
				score : scores.military_destroyed[1],
				rank : scores.military_destroyed[0],
				className : 'hImproved_military_destroyed'
			});
			
			// Military lost.
			fillScoresCell(scoreTBody.rows[3].cells[1], {
				desc : 'Lost: ',
				score : scores.military_lost[1],
				rank : scores.military_lost[0],
				className : 'hImproved_military_lost'
			});
			
			// Defense.
			fillScoresCell(scoreTBody.rows[4].cells[0], {
				desc : 'Defense: ',
				score : scores.defenseActual,
				percentage : scores.defensePercentage,
				className : 'hImproved_defense'
			});
			
			// Honor.
			fillScoresCell(scoreTBody.rows[4].cells[1], {
				desc : 'Honor: ',
				score : scores.honor[1],
				rank : scores.honor[0],
				className : 'hImproved_honor'
			});
			
			// Planets table
			var planetsTable = document.createElement('table');
			planetsTable.setAttribute('class', 'hImproved_planets');
			planetsTable.setAttribute('style', 'display: none');
			var planetsTBody = document.createElement('tBody');
			planetsTable.appendChild(planetsTBody);
			
			var row, cell, link;
			var link_sort = Array(3);
			planetsTable.createTHead();
			row = document.createElement('tr');
			row.setAttribute('class', 'hImproved_tableHead');
			cell = document.createElement('td');
			cell.setAttribute('class', 'hImproved_planetnumber');
			link_sort[0] = document.createElement('a');
			link_sort[0].setAttribute('class', 'hImproved_sortable');
			link_sort[0].setAttribute('href', 'javascript:void(0)');
			link_sort[0].appendChild(document.createTextNode(L('rank_sign')));
			cell.appendChild(link_sort[0]);
			row.appendChild(cell);
			cell = document.createElement('td');
			link_sort[1] = document.createElement('a');
			link_sort[1].setAttribute('class', 'hImproved_sortable');
			link_sort[1].setAttribute('href', 'javascript:void(0)');
			link_sort[1].appendChild(document.createTextNode(L('Planet')));
			cell.appendChild(link_sort[1]);
			cell.setAttribute('class', 'hImproved_planet');
			row.appendChild(cell);
			cell = document.createElement('td');
			link_sort[2] = document.createElement('a');
			link_sort[2].setAttribute('class', 'hImproved_sortable');
			link_sort[2].setAttribute('href', 'javascript:void(0)');
			link_sort[2].appendChild(document.createTextNode(L('Coordinate')));
			cell.appendChild(link_sort[2]);
			row.appendChild(cell);
			planetsTable.tHead.appendChild(row);
			
			var planets = data[playerId].planets;
			
			if (planets.length > 0)
			{
				for (var i = 0; i < planets.length; i++)
				{
					row = document.createElement('tr');
					row.setAttribute('class', 'hImproved_' + (i % 2 ? 'odd' : 'even'));
					
					cell = document.createElement('td');
					cell.appendChild(document.createTextNode(''));
					cell.setAttribute('class', 'hImproved_planetnumber');
					row.appendChild(cell);
					
					cell = document.createElement('td');
					cell.appendChild(document.createTextNode(''));
					cell.setAttribute('class', 'hImproved_planet');
					row.appendChild(cell);
					
					cell = document.createElement('td');
					link = document.createElement('a');
					link.appendChild(document.createTextNode(''));
					cell.appendChild(link);
					cell.setAttribute('class', 'hImproved_coords');
					row.appendChild(cell);
					
					planetsTBody.appendChild(row);
				}
				
				fillPlanets(playerId, planetsTable);
			}
			else
			{
				row = document.createElement('tr');
				cell = document.createElement('td');
				cell.setAttribute('colspan', '3');
				cell.appendChild(document.createTextNode(L("No planets found for this player. It may take some time until the data is available by the OGame server.")));
				row.appendChild(cell);
				
				planetsTBody.appendChild(row);
			}
			
			container.appendChild(planetsTable);
			
			// Add event handler for tabs
			link_scores.addEventListener('click', function () { scoreTable.setAttribute('style', 'display: table'); planetsTable.setAttribute('style', 'display: none'); }, false);
			link_planets.addEventListener('click', function () { scoreTable.setAttribute('style', 'display: none'); planetsTable.setAttribute('style', 'display: table'); }, false);
			
			for (var i = 0; i < link_sort.length; i++)
			{
				link_sort[i].addEventListener('click', function(category) { return function () { sortPlanets.apply(this, [playerId, category]); } }(i));
			}
		}
	}
	
	function fillScoresCell(cell, params)
	{
		var span, elm;
		span = document.createElement('span');
		if (params.tooltip)
		{
			span.setAttribute('class', 'tooltipRight');
			var title = '';
			for (var i = 0; i < params.tooltip.length; i++)
			{
				title += L(params.tooltip[i]);
			}
			span.setAttribute('title', title);
		}
		span.appendChild(document.createTextNode(L(params.desc)));
		elm = document.createElement('span');
		elm.appendChild(document.createTextNode(addSeperator(params.score)));
		elm.setAttribute('class', 'hImproved_score');
		span.appendChild(elm);
		if (params.rank)
		{
			span.appendChild(document.createTextNode(' '));
			elm = document.createElement('span');
			elm.appendChild(document.createTextNode(L('rank_sign') + addSeperator(params.rank)));
			elm.setAttribute('class', 'hImproved_rank');
			span.appendChild(elm);
		}
		if (params.percentage)
		{
			// Percent with one decimal.
			params.percentage = Math.round(params.percentage * 1000) / 10;
			
			span.appendChild(document.createTextNode(' '));
			elm = document.createElement('span');
			elm.appendChild(document.createTextNode('(' + params.percentage + L('percent_sign') + ')'));
			elm.setAttribute('class', 'hImproved_percent');
			span.appendChild(elm);
		}
		cell.appendChild(span);
		cell.setAttribute('class', params.className);
	}
	
	function fillPlanets(playerId, table)
	{
		if (typeof table == "undefined")
		{
			// Get planets table.
			table = document.getElementById('hImproved_information_' + playerId);
			table = table.getElementsByClassName('hImproved_planets');
			if (table.length < 1)
			{
				return;
			}
			table = table[0];
		}
		
		var link, coords, row;
		var tBody = table.tBodies[0];
		var planets = data[playerId].planets;
		for (var i = 0; i < planets.length; i++)
		{
			row = tBody.rows[i];
			// Homeplanet
			if (planets[i][0] == 1)
			{
				addClass(row, 'hImproved_home');
			}
			else
			{
				removeClass(row, 'hImproved_home');
			}
		
			// Planet number
			row.cells[0].firstChild.nodeValue = planets[i][0];
		
			// Planet name
			row.cells[1].firstChild.nodeValue = planets[i][1];
		
			// Planet coordinate
			link = row.cells[2].firstChild;
			coords = planets[i][2].split(':');
			if (coords.length > 1)
			{
				link.setAttribute('href', '?page=galaxy&galaxy=' + coords[0] + '&system=' + coords[1]);
			}
			else
			{
				link.setAttribute('href', '#');
			}
			link.firstChild.nodeValue = planets[i][2] + (planets[i][3] ? L("moon_abbr") : '');
		}
		
		// Fix table head sort icons
		row = table.tHead.rows[0];
		for (var i = 0; i < row.cells.length; i++)
		{
			link = row.cells[i].firstChild;
			removeClass(link, 'hImproved_asc');
			removeClass(link, 'hImproved_desc');
			if (i == config.planetListSortCategory)
			{
				addClass(link, (config.planetListSortAscending ? 'hImproved_asc' : 'hImproved_desc'));
			}
		}
	}
	
	// Sort planets of a player by category
	function sortPlanets(playerId, category)
	{
		if (category == config.planetListSortCategory)
		{
			config.planetListSortAscending = !config.planetListSortAscending;
		}
		else
		{
			config.planetListSortCategory = category;
			config.planetListSortAscending = true;
		}
		
		// Actually sort
		data[playerId].planets.sort(sortPlanetsComparison);
		
		fillPlanets(playerId);
	}
	
	// Comparison function for planet sorting
	function sortPlanetsComparison(a, b)
	{
		var factor = (config.planetListSortAscending ? 1 : -1);
		
		if (config.planetListSortCategory == 1)
		{
			if (a[1] < b[1])
			{
				return -1 * factor;
			}
			else if (a[1] > b[1])
			{
				return 1 * factor;
			}
		}
		else if (config.planetListSortCategory == 2)
		{
			var coords = [];
			coords.push(a[2].split(':'));
			coords.push(b[2].split(':'));
			for (var i = 0; i < coords.length; i++)
			{
				for (var j = 0; j < coords[i].length; j++)
				{
					coords[i][j] = parseInt(coords[i][j]);
				}
			}
			
			if (coords[0].length > 2 && coords[1].length > 2)
			{
				// Galaxy
				if (coords[0][0] < coords[1][0])
				{
					return -1 * factor;
				}
				else if (coords[0][0] > coords[1][0])
				{
					return 1 * factor;
				}
				// System
				else if (coords[0][1] < coords[1][1])
				{
					return -1 * factor;
				}
				else if (coords[0][1] > coords[1][1])
				{
					return 1 * factor;
				}
				// Planet
				else if (coords[0][2] < coords[1][2])
				{
					return -1 * factor;
				}
				else if (coords[0][2] > coords[1][2])
				{
					return 1 * factor;
				}
			}
		}
		
		// Sort normal if category comparison is equal
		// Check unique planet number
		return (a[0] - b[0]) * factor;
	}
	
	function scroll(evt)
	{
		var scrollTop = (window.pageYOffset || (document.body && document.body.scrollTop));
		var elemTop = 0;
		var send = document.getElementById('send');
		var elem = send;
		do
		{
			elemTop += elem.offsetTop;
			elem = elem.offsetParent;
		}
		while (elem);
		
		if (scrollTop > elemTop)
			send.setAttribute('class', 'improve');
		else
			send.setAttribute('class', '');
	}
	
	function nodeInserted(evt)
	{
		if(!evt || !evt.target || !evt.target.childElementCount || evt.target.childElementCount < 1 || !evt.relatedNode || !evt.relatedNode.id || evt.relatedNode.id != 'stat_list_content')
			return;
		var ranks = document.getElementById('ranks');
		if (!ranks)
			return;
		
		modifyPageBar();
		
		var navigationRow = document.getElementById('row');
		var active = navigationRow.getElementsByClassName('active');
		if (active.length == 0 || active[0].getAttribute('id') == 'alliance')
			return;
		
		var tBody = ranks.tBodies[0];
		
		// Show ship count next to the military score
		if (config.showShips && active.length == 2 && active[1].getAttribute('id') == 'fleet')
		{
			for (var i = 0; i < tBody.rows.length; i++)
			{
				var td = tBody.rows[i].getElementsByClassName('score');
				if (td && td.length > 0)
				{
					var title = td[0].getAttribute('title');
					if (title && title.length > 0)
					{
						var points = title.substring(title.lastIndexOf(' ') + 1);
						var span = document.createElement('span');
						span.setAttribute('class', 'shipcount');
						span.appendChild(document.createTextNode('(' + points + ')'));
						
						td[0].appendChild(document.createElement('br'));
						td[0].appendChild(span);
					}
					else
					{
						break;
					}
				}
			}
		}
		
		// Show information beneath the player
		if (config.extendedInformation)
		{
			addExtendedInformationToggles(tBody);
		}
	}
	
	function addExtendedInformationToggles(tBody)
	{
		var a = document.createElement('a');
		a.setAttribute('class', 'extendedInfoToggle');
		a.setAttribute('href', 'javascript:void(0)');
		
		for (var i = 0; i < tBody.rows.length; i++)
		{
			var td = tBody.rows[i].getElementsByClassName('score');
			if (td && td.length > 0)
			{
				var tmp = a.cloneNode(true);
				tmp.addEventListener('click', toggleExtendedInformation, false);
				td[0].appendChild(tmp);
			}
		}
	}
	
	function toggleExtendedInformation(evt)
	{
		var playerId;
		var infoRow;
		var expand = true;
		var row = evt.target.parentNode.parentNode;
		// Get the player id.
		var sendMessage = row.getElementsByClassName('sendmsg');
		if (sendMessage.length > 0)
		{
			var sendMessageLinks = sendMessage[0].getElementsByTagName('a');
			if (sendMessageLinks.length > 0)
			{
				/*var expr = /&playerId=(\d*)/;
				var result = expr.exec(sendMessageLinks[0].getAttribute('href'));
                if (result != null)
				{
					playerId = result[1];
				}*/
                playerId = parseInt(sendMessageLinks[0].getAttribute('data-playerid'));
			}
			else
			{
				// The player has clicked himself.
				var ogamePlayerId = document.getElementsByName('ogame-player-id');
				if (ogamePlayerId.length > 0)
				{
					playerId = parseInt(ogamePlayerId[0].getAttribute('content'));
				}
			}
		}
		else
		{
			return;
		}
		
		// Get the row used to show the information.
		infoRow = document.getElementById('hImproved_information_' + playerId);
		
		if (!infoRow)
		{
			// No row found create one and load the data.
			infoRow = document.createElement('tr');
			infoRow.setAttribute('class', 'hImproved_information');
			infoRow.setAttribute('id', 'hImproved_information_' + playerId);
			var td = document.createElement('td');
			td.setAttribute('colspan', '5');
			td.appendChild(document.createTextNode(L('Loading... ')));
			var span = document.createElement('span');
			span.appendChild(document.createTextNode('0.0'));
			span.setAttribute('name', 'hImproved_loading');
			td.appendChild(span);
			td.appendChild(document.createTextNode(L('percent_sign')));
			infoRow.appendChild(td);
			
			// Add behind the clicked row.
			row.parentNode.insertBefore(infoRow, row.nextSibling);
			
			
			showData(playerId, td);
		}
		
		if (hasClass(evt.target, 'extendedInfoToggleExpanded'))
		{
			expand = false;
			removeClass(evt.target, 'extendedInfoToggleExpanded');
		}
		else
		{
			addClass(evt.target, 'extendedInfoToggleExpanded');
		}
		
		infoRow.style.display = (expand ? 'table-row' : 'none');
		
		return false;
	}
	
	// Adds a needed class and optionally creates first/last page links.
	function modifyPageBar()
	{
		var pageBar = document.getElementsByClassName("pagebar");
		if (pageBar.length < 1)
			return;
		
		pageBar[0].setAttribute('class', pageBar[0].getAttribute('class') + ' hImproved_firstBar');
		
		// Show first and last page switch
		if (config.nextPrevPageLink)
		{
			var pageBarActive = pageBar[0].getElementsByClassName('activePager');
			if (pageBarActive.length > 0)
			{
				var prevLink = pageBarActive[0].previousSibling;
				var nextLink = pageBarActive[0].nextSibling;
				var hasFirstPageLink = false;
				var hasLastPageLink = false;
				
				// Find A node before and behind the selected page.
				while (prevLink && prevLink.nodeType != 1)
				{
					prevLink = prevLink.previousSibling;
				}
				while (nextLink && nextLink.nodeType != 1)
				{
					nextLink = nextLink.nextSibling;
				}
				
				// Check if there is first page link. Since first node contains whitespaces use second node.
				if (isNaN(parseInt(pageBar[0].firstChild.nextSibling.firstChild.nodeValue)))
				{
					hasFirstPageLink = true;
				}
				
				// Check if there is last page link. If the last page is selected the last node is a text node which has no children.
				if (pageBar[0].lastChild.previousSibling.firstChild && isNaN(parseInt(pageBar[0].lastChild.previousSibling.firstChild.nodeValue)))
				{
					hasLastPageLink = true;
				}
				
				for (var bar = 0; bar < pageBar.length; bar++)
				{
					// Fix whitespace nodes so that links can be inserted with correct "margin".
					if (pageBar[bar].firstChild.nodeType == 3)
					{
						pageBar[bar].firstChild.nodeValue = '\u00a0 ';
					}
					if (pageBar[bar].lastChild.nodeType == 3)
					{
						pageBar[bar].removeChild(pageBar[bar].lastChild);
					}
					
					if (prevLink)
					{
						var node;
						prevLink = prevLink.cloneNode(false);
						prevLink.appendChild(document.createTextNode("<"));
						if (hasFirstPageLink)
						{
							node = pageBar[bar].firstChild.nextSibling.nextSibling;
							if (bar == 1)
							{
								node = node.nextSibling.nextSibling;
							}
							pageBar[bar].insertBefore(document.createTextNode("\u00a0 "), node);
							pageBar[bar].insertBefore(prevLink, node);
						}
						else
						{
							node = pageBar[bar].firstChild;
							// Ignore "to top" button
							if (bar == 1)
							{
								node = node.nextSibling.nextSibling.nextSibling;
								node = pageBar[bar].insertBefore(document.createTextNode("\u00a0 "), node);
							}
							pageBar[bar].insertBefore(prevLink, node);
						}
					}
					if (nextLink)
					{
						nextLink = nextLink.cloneNode(false);
						nextLink.appendChild(document.createTextNode(">"));
						if (hasLastPageLink)
						{
							pageBar[bar].insertBefore(nextLink, pageBar[bar].lastChild);
							pageBar[bar].insertBefore(document.createTextNode("\u00a0 "), pageBar[bar].lastChild);
						}
						else
						{
							pageBar[bar].appendChild(document.createTextNode("\u00a0 "));
							pageBar[bar].appendChild(nextLink);
						}
					}
				}
			}
		}
	}
})();