mrgenis / OGame 5: Formulas

// ==UserScript==
// @version     1.1.2
// @name        OGame 5: Formulas
// @autor       Sergio Flores Genis (MrGenis)
// @oujs:autor  mrgenis
// @date        2015-09-23
// @namespace   OGame
// @description Formulas de OGame 5
// @include     http://*.ogame.gameforge.*/game/*
// @exclude     *
// @grant       none
// ==/UserScript==
Math.trunc = Math.trunc || function (x) { return x < 0 ? Math.ceil(x) : Math.floor(x); };
function byId(id) { return document.getElementById(id); }
var win = (typeof unsafeWindow) == 'undefined' ? window : unsafeWindow;

function _fnOGame() {
	var root = this;

	/**
	 * Define propiedades en la raiz del objeto _fnOGame (root)
	 * @param key Nombre de la propiedad a definir
	 * @param value valor asignado a la propiedad
	 * @param e indica si es enumerable (def : true)
	 * @param w indica si se puede escribir (def : false)
	 * @param c indica si puede ser reconfigurable (def : false)
	 * @returns Propiedad creada
	 */
	function _define(key, value, e, w, c) {
		var config = {};
		config.enumerable = ('undefined' === typeof(e)) ? true : e;
		config.writable = ('undefined' === typeof(w)) ? false : w;
		config.configurable = ('undefined' === typeof(c)) ? false : c;
		if ('undefined' !== typeof(value)
			|| null != value) config.value = value;
		return Object.defineProperty(root, key, config);
	};
	
	_define('server_time', win.startServerTime + win.timeDiff);
	_define('server_version', root.meta('ogame-version'));
	_define('currentPage', win.currentPage);
	_define('currentPlanetType', root.meta('ogame-planet-type'));
	_define('currentPlanetId', parseInt(root.meta('ogame-planet-id')) );

	_define('isPage', function(p){
		return (p === root.currentPage);
	});
	
	/* ======================================================================= */
	/* ============================== Tienda ================================= */
	/* ======================================================================= */
	
	_define('items',{
		metal10 : 'de922af379061263a56d7204d1c395cefcfb7d75',
		metal20 : 'ba85cc2b8a5d986bbfba6954e2164ef71af95d4a',
		metal30 : '05294270032e5dc968672425ab5611998c409166',
		metalFP10 : 'b956c46faa8e4e5d8775701c69dbfbf53309b279',
		crystal10 : '3c9f85221807b8d593fa5276cdf7af9913c4a35d',
		crystal20 : '422db99aac4ec594d483d8ef7faadc5d40d6f7d3',
		crystal30 : '118d34e685b5d1472267696d1010a393a59aed03',
		crystalFP10: '090a969b05d1b5dc458a6b1080da7ba08b84ec7f',
		deuterium10 : 'd9fa5f359e80ff4f4c97545d07c66dbadab1d1be',
		deuterium20 : 'e4b78acddfa6fd0234bcb814b676271898b0dbb3',
		deuterium30 : '5560a1580a0330e8aadf05cb5bfe6bc3200406e2',
		deuteriumFP10: 'e254352ac599de4dd1f20f0719df0a070c623ca8'
	}, true);
	
	/* ####################################################################### */

	/* ======================================================================= */
	/* ============== Objeto para el almacenamiento de datos ================= */
	/* ======================================================================= */

	function _oStorage() {
		var skey = root.meta('ogame-universe').split('.')[0];
		Object.defineProperty(this, 'mask', {
			value : '$OGame#' + skey + '.',
			enumerable : true,
			configurable : false,
			writable : false
		});
	};

	_oStorage.prototype.set = function (key, value) {
		value = JSON.stringify(value);
		return localStorage.setItem(this.mask + key, value);
	};

	_oStorage.prototype.get = function (key) {
		var raw = localStorage.getItem(this.mask + key) || 0;
		return JSON.parse(raw);
	};

	_oStorage.prototype.has = function (key) {
		return (this.get(key) !== 0);
	};

	_oStorage.prototype.remove = function (key) {
		localStorage.removeItem(key);
	};

	_define('Storage', new _oStorage());

	/* ####################################################################### */

	
	/* ======================================================================= */
	/* ================== Cargando informacion del universo ================== */
	/* ======================================================================= */

	(function() {

		/** root.server (enumerable) */
		function _loadUniverse() {
			var information = root.Storage.get('server'),
			ajax = jQuery.Deferred();
			if (!information) {
				ajax = jQuery.ajax({
						method : 'get', url : '/api/serverData.xml',
						cache : true, dataType : 'xml', global : false,
						success : function (data, status, xhr) {
							var xml = jQuery(data.firstChild),
							information = {};
							xml.children().each(function (i, o) {
								information[o.nodeName] = o.innerHTML;
							});
							information['serverId'] = data.firstChild.getAttribute('serverId');
							information['timeread'] = data.firstChild.getAttribute('timestamp');
							root.Storage.set('server', information);
						}
					});
			} else {
				ajax.resolve("$OGame.server");
				ajax = ajax.promise();
			}
			_define('server', information);
			return ajax;
		};

		function _loadLocalization() {
			var information = root.Storage.get('server_localization'),
			ajax = jQuery.Deferred();
			if (!information) {
				ajax = jQuery.ajax({
					method : 'get', url : '/api/localization.xml',
					cache : true, dataType : 'xml', global : false,
					success : function (data, status, xhr) {
						var xml = data.firstChild,
						nodes = xml.childNodes,
						information = {};
						// tech
						var tech = nodes.item(0),
						items = tech.childElementCount;
						for (var i = 0; i<items ; i++) {
							var child = tech.children.item(i);
							information[ child.id ] = child.innerHTML;
						}

						// missions
						var mission = nodes.item(1);
						items = mission.childElementCount;
						for( i = 0; i<items; i++) {
							var child = mission.children.item(i);
							information[ 'm'+child.id ] = child.innerHTML;
						}
						root.Storage.set('server_localization', information);
					}
				});
			} else {
				ajax.resolve("$OGame.server_localization");
				ajax = ajax.promise();
			}
			_define('_namesData', information, false);
			return ajax;
		};

	
		var loader = jQuery.when(
			_loadUniverse(),
			_loadLocalization()
		);
		_define('defered', function () {
			return loader;
		}, true);
	})();

	/* ####################################################################### */


	/* ======================================================================= */
	/* ======================== Nombres de estructuras ======================= */
	/* ======================================================================= */

	(function (page) {

		var _localization_ = win.LocalizationStrings;

		_localization_.names = function (key) {
			if ('undefined' === typeof(root._namesData[key]))
				return 'LN' + key;
			return root._namesData[key];
		};
		_define('Localization', _localization_);

	})(root.currentPage);

	/* ####################################################################### */

	
	/* ======================================================================= */
	/* ============================ Equipo comando =========================== */
	/* ======================================================================= */

	(function () {

		root.officers = {
			commander : (byId('officers').getElementsByClassName('commander')[0].className.indexOf('on') != -1),
			admiral : (byId('officers').getElementsByClassName('admiral')[0].className.indexOf('on') != -1),
			admiral_fleet : 0,
			geologist : (byId('officers').getElementsByClassName('geologist')[0].className.indexOf('on') != -1),
			geologist_mines : 0,
			technocrat : (byId('officers').getElementsByClassName('technocrat')[0].className.indexOf('on') != -1),
			technocrat_spy : 0,
			technocrat_research : 1,
			engineer : (byId('officers').getElementsByClassName('engineer')[0].className.indexOf('on') != -1),
			enginner_energy : 1,
			all : (byId('officers').className.indexOf('all') != -1)
		};
		_define('allOfficers', root.officers.all);

		if (root.allOfficers) {
			root.officers.admiral_fleet = 3;
			root.officers.enginner_energy = 1.12;
			root.officers.geologist_mines = 0.12;
			root.officers.technocrat_spy = 3;
			root.officers.technocrat_research = 1.25;
		} else {
			if (root.officers.admiral)
				root.officers.admiral_fleet = 2;
			if (root.officers.engineer)
				root.officers.enginner_energy = 1.1;
			if (root.officers.geologist)
				root.officers.geologist_mines = 0.1;
			if (root.officers.technocrat) {
				root.officers.technocrat_spy = 2;
				root.officers.technocrat_research = 1.25;
			}
		}

		Object.defineProperty(root, 'officers', {
			writable : false,
			configurable : false
		});
		Object.freeze(root.officers);

	})();

	/* ####################################################################### */

	
	/* ======================================================================= */
	/* ========================== Naves y defenzas =========================== */
	/* ======================================================================= */

	(function (root) {

		/**
		 * (constructor) Objeto para guardar al costo base de un elemento
		 * @param m : costo en metal
		 * @param c : costo en cristal
		 * @param d : costo en deuterio
		 */
		function _costo(m, c, d) {
			Object.defineProperty(this, 'metal', {
				value : m,
				enumerable : true
			});
			Object.defineProperty(this, 'crystal', {
				value : c,
				enumerable : true
			});
			Object.defineProperty(this, 'deuterium', {
				value : d,
				enumerable : true
			});
		}

		/**
		 * (constructor) Objeto que reprecenta una defensa
		 * @param m : costo en metal
		 * @param c : costo en cristal
		 * @param d : costo en deuterio
		 */
		function _defence(m, c, d) {
			_costo.call(this, m, c, d);
		};
		_defence.prototype = Object.create(_costo.prototype);
		_defence.prototype.constructor = _defence;
		_defence.prototype.fnTimeProduction = function (n, shipyard, nanite) {
			var time = 3600 * ((this.metal + this.crystal) / 5000 * 2 / (shipyard + 1.0) * Math.pow(0.5, nanite));
			return (Math.floor(time) * n) / root.server.speed;
		};
		Object.defineProperty(root.Object, 'oDefence', {
			enumerable : true,
			value : function (m, c, d) {
				return new _defence(m, c, d);
			}
		});

		/**
		 * (constructor) Objeto que reprecenta una nave
		 * @param m : costo en metal
		 * @param c : costo en cristal
		 * @param d : costo en deuterio
		 * @param s : capacidad de carga
		 */
		function _ship(m, c, d, s) {
			_defence.call(this, m, c, d);
			Object.defineProperty(this, 'capacity', {
				value : s,
				enumerable : true
			});
		};
		_defence.prototype = Object.create(_defence.prototype);
		_defence.prototype.constructor = _ship;
		Object.defineProperty(root.Object, 'oShip', {
			enumerable : true,
			value : function (m, c, d, s) {
				return new _ship(m, c, d, s);
			}
		});

	})(root);

	this.defences = {
		/* Lanzamisiles    */
		401 : root.Object.oDefence(2000, 0, 0),
		/* Lázer pequeño   */
		402 : root.Object.oDefence(1500, 500, 0),
		/* Lázer grande    */
		403 : root.Object.oDefence(6000, 2000, 0),
		/* Cañon guass     */
		404 : root.Object.oDefence(20000, 15000, 2000),
		/* Cañon iónico    */
		405 : root.Object.oDefence(2000, 6000, 0),
		/* Caño de plasma  */
		406 : root.Object.oDefence(50000, 50000, 30000),
		/* Cúpula pequeña  */
		407 : root.Object.oDefence(10000, 10000, 0),
		/* Cúpula grande   */
		408 : root.Object.oDefence(50000, 50000, 0),
		/* Intercepción    */
		502 : root.Object.oDefence(8000, 0, 2000),
		/* Interplanetario */
		503 : root.Object.oDefence(12500, 2500, 10000)
	};

	this.ships = {
		/* Cazador ligero  */
		204 : root.Object.oShip(3000, 1000, 0, 50),
		/* Cazador pesado  */
		205 : root.Object.oShip(6000, 4000, 0, 100),
		/* Crucero         */
		206 : root.Object.oShip(20000, 7000, 2000, 800),
		/* Nave de batalla */
		207 : root.Object.oShip(45000, 15000, 0, 1500),
		/* Acorazado       */
		215 : root.Object.oShip(30000, 40000, 15000, 750),
		/* Bombardero      */
		211 : root.Object.oShip(50000, 25000, 15000, 500),
		/* Destructor      */
		213 : root.Object.oShip(60000, 50000, 15000, 2000),
		/* EDL Muerte      */
		214 : root.Object.oShip(5000000, 4000000, 1000000, 1000000),
		/* NP de carga     */
		202 : root.Object.oShip(2000, 2000, 0, 5000),
		/* NG de carga     */
		203 : root.Object.oShip(6000, 6000, 0, 25000),
		/* Nave de colonia */
		208 : root.Object.oShip(10000, 20000, 10000, 7500),
		/* Reciclador      */
		209 : root.Object.oShip(10000, 6000, 2000, 20000),
		/* Sonda espionaje */
		210 : root.Object.oShip(0, 1000, 0, 5),
		/* Satélite solar  */
		212 : root.Object.oShip(0, 2000, 500, 0)
	};

	/* ####################################################################### */
	
	
	/* ======================================================================= */
	/* ======================== Energia y produccion ========================= */
	/* ======================================================================= */
	
	function _energyMetalCrystal(level, power) {
		return Math.ceil(power * 10 * level * Math.pow(1.1, level));
	}
	this.energy = {};
	_define('energy', {
		metal : _energyMetalCrystal,
		crystal : _energyMetalCrystal,
		deuterium : function (level, power) {
			return Math.ceil(power * 20 * level * Math.pow(1.1, level));
		},
		solar : function (level, power) {
			return Math.floor(power * engineer * (20 * level * Math.pow(1.1, level)));
		},
		fusion : function (level, power, techEnergy) {
			return Math.floor(power * engineer * (30 * level * Math.pow(1.05 + techEnergy * 0.01, level)));
		},
		satellite : function (count, power, temp) {
			var s = Math.floor(count * power * engineer * Math.floor((temp + 140) / 6));
			return (s < 0) ? 0 : s;
		},
		factor : function (metal, metalPower,
			crystal, crystalPower, deuterium, deuteriumPower,
			solar, solarPower, fusion, fusionPower, satellite, satellitePower, temp, techEnergy) {

			var koeff = 1,
			used = f.energy.metal(metal, metalPower)
				 + f.energy.crystal(crystal, crystalPower)
				 + f.energy.deuterium(deuterium, deuteriumPower),
			produced = f.energy.solar(solar, solarPower)
				 + f.energy.fusion(fusion, fusionPower, techEnergy)
				 + f.energy.satellite(satellite, satellitePower, temp);
			if (used > 0) koeff = produced / (1.0 * used);
			if (koeff > 1) koeff = 1;
			return {
				koeff : koeff,
				produced : produced,
				used : used,
				diff : produced - used
			};
		}
	}, true);
	Object.freeze(root.energy);
	
	function _amplifierById( id ) {
		
		if (id == root.items.metal10
				|| id == root.items.metalFP10
				|| id == root.items.crystal10
				|| id == root.items.crystalFP10
				|| id == root.items.deuterium10
				|| id == root.items.deuteriumFP10 ) {
			
			return 0.1;
		} else if( id == root.items.metal20
				|| id == root.items.crystal20
				|| id == root.items.deuterium20 ) {
		
			return 0.2;
		} else if ( id == root.items.metal30
				|| id == root.items.crystal30
				|| id == root.items.deuterium30 ) {
			
			return 0.3;
		}
	};
	function _production(base, mine, plasm, obj) {
		var geol = mine + root.officers.geologist_mines,
		mg = Math.ceil(mine + geol);
		plasm = mine * plasm;
		obj = mine * _amplifierById(obj);
		return {
			production : Math.round(base + mg + plasm + object),
			resources : {income:base, mine:Math.round(mine), geologist:Math.round(geol),
				plasma:Math.round(plasm), object:Math.round(obj)}
		};
	}
	_define('production', {
		metal : function(level, object, power, koeff, plasma) {
			var base = (30 * speed),
					mine = (speed * power * koeff * 30 * level * Math.pow(1.1, level)) ;
			plasma = plasma / 100;
			return _production(base, mine, plasma, object);
		},
		crystal : function(level, object, power, koeff, plasma) {
			var base = (15 * speed),
					mine = (speed * power * koeff * 20 * level * Math.pow(1.1, level)) ;
			plasma = (plasma * 66) / 10000;
			return _production(base, mine, plasma, object);
		},
		deuterium : function(level, object, power, koeff, temp) {
			var mine = (speed * power * koeff 
									* 10 * level * Math.pow(1.1, level) * (1.44 - 0.004 * temp));
			return _production(0, mine, 0, object);
		},
		fusion : function(level, power){
			return (speed * power * 10 * level * Math.pow(1.1, level));
		}
	}, true);
	
	
	/* ####################################################################### */
	
};

_fnOGame.prototype.Object = {};

_fnOGame.prototype.meta = function(key) {
	return document.getElementsByName(key)[0].content;
};

_fnOGame.prototype.fnStorage = function (l) {
	if (NaN === l || 'undefined' === typeof(l)) return NaN;
	return 5000 * Math.trunc(2.5 * Math.pow(Math.E, (20 * l) / 33));
};

_fnOGame.prototype.fnTimeResearch = function (metal, crystal, lab) {
	return ((metal + crystal) / 1000 * (1 + lab)) * this.server.speed;
}

_fnOGame.prototype.fnTitle = function (e) {
	if ('string' == typeof(e))
		e = jQuery(e)[0];
	if ('undefined' == typeof(e))
		return '';
	var tx = (e.title == '') ? jQuery(e).data('tipped_restore_title') : e.title;
	return tx;
};

_fnOGame.prototype.fnTimespanToShorten = function (seconds, minimize) {
	if ('undefine' === typeof(minimize))
		minimize = true;
	var localization = this.Localization.timeunits;
	if (seconds == 0)
		return '0' + localization.short.second;
	var timeStr = '',
	haveWeek = false,
	haveDay = false;

	if (seconds >= 604800) {
		// el tiempo es 1 SEMANA o mas
		timeStr += Math.floor(seconds / 604800);
		timeStr += localization.short.week + ' ';
		seconds = seconds % 604800;
		haveWeek = true;
	}

	if (seconds >= 86400 || timeStr.length > 0) {
		// el tiempo es mayor o igual a 1 DIA
		// ya se a definido texto antes.
		if (seconds / 86400 >= 1) {
			timeStr += Math.floor(seconds / 86400);
			timeStr += localization.short.day + ' ';
		}
		seconds = seconds % 86400;
		haveDay = true;
	}

	if (seconds >= 3600 || timeStr.length > 0) {
		// el tiempo es mayor o igual a 1 HORA
		// ya se a definido texto antes.
		if (seconds / 3600 >= 1) {
			timeStr += Math.floor(seconds / 3600);
			timeStr += localization.short.hour + ' ';
		}
		seconds = seconds % 3600;
	}

	if (minimize && haveWeek)
		return timeStr;
	if (seconds >= 60 || timeStr.length > 0) {
		// timepo es mayor o igual a 1 MINUTO
		if (seconds / 60 >= 1) {
			timeStr += Math.floor(seconds / 60);
			timeStr += localization.short.minute + ' ';
		}
		seconds = seconds % 60;
	}

	if (minimize && haveDay)
		return timeStr;
	if (seconds > 0) {
		// el tiempo tiene segundos
		timeStr += Math.floor(seconds);
		timeStr += localization.short.second;
	}

	return timeStr;
};

_fnOGame.prototype.fnNumberHumanReadable = function(num, cut) {
	num = num || 0;
	cut = cut || 3;
	return win.gfNumberGetHumanReadable(num, cut);
};

var $OGame = new _fnOGame();
win.$OGame = $OGame;