NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name InfoCompte
// @namespace https://openuserjs.org/users/The_Stubbs
// @version 9.0.11
// @description InfoCompte script for OGame
// @author Vulca, benneb & now The Stubbs
// @license MIT
// @match https://*.ogame.gameforge.com/game/*
// @updateURL https://openuserjs.org/meta/The_Stubbs/InfoCompte.meta.js
// @downloadURL https://openuserjs.org/install/The_Stubbs/InfoCompte.user.js
// @grant none
// @run-at document-idle
// @watch WxhTbxMSvT0
// @todo V9, Buildings order, Safari
// ==/UserScript==
const GameData = {
costs: {
1: [ 60, 15, 0, 1.5 ],
2: [ 48, 24, 0, 1.6 ],
3: [ 225, 75, 0, 1.5 ],
4: [ 75, 30, 0, 1.5 ],
12: [ 900, 360, 180, 1.8 ],
14: [ 400, 120, 200, 2 ],
15: [ 1000000, 500000, 100000, 2 ],
21: [ 400, 200, 100, 2 ],
22: [ 1000, 0, 0, 2 ],
23: [ 1000, 500, 0, 2 ],
24: [ 1000, 1000, 0, 2 ],
31: [ 200, 400, 200, 2 ],
33: [ 0, 50000, 100000, 2 ],
34: [ 20000, 40000, 0, 2 ],
36: [ 200, 0, 50, 5 ],
41: [ 20000, 40000, 20000, 2 ],
42: [ 20000, 40000, 20000, 2 ],
43: [ 2000000, 4000000, 2000000, 2 ],
44: [ 20000, 20000, 1000, 2 ],
106: [ 200, 1000, 200, 2 ],
108: [ 0, 400, 600, 2 ],
109: [ 800, 200, 0, 2 ],
110: [ 200, 600, 0, 2 ],
111: [ 1000, 0, 0, 2 ],
113: [ 0, 800, 400, 2 ],
114: [ 0, 4000, 2000, 2 ],
115: [ 400, 0, 600, 2 ],
117: [ 2000, 4000, 600, 2 ],
118: [ 10000, 20000, 6000, 2 ],
120: [ 200, 100, 0, 2 ],
121: [ 1000, 300, 100, 2 ],
122: [ 2000, 4000, 1000, 2 ],
123: [ 240000, 400000, 160000, 2 ],
124: [ 4000, 8000, 4000, 1.75 ],
199: [ 0, 0, 0, 3 ],
202: [ 2000, 2000, 0 ],
203: [ 6000, 6000, 0 ],
204: [ 3000, 1000, 0 ],
205: [ 6000, 4000, 0 ],
206: [ 20000, 7000, 2000 ],
207: [ 45000, 15000, 0 ],
208: [ 10000, 20000, 10000 ],
209: [ 10000, 6000, 2000 ],
210: [ 0, 1000, 0 ],
211: [ 50000, 25000, 15000 ],
212: [ 0, 2000, 500 ],
213: [ 60000, 50000, 15000 ],
214: [ 5000000, 4000000, 1000000 ],
215: [ 30000, 40000, 15000 ],
217: [ 2000, 2000, 1000 ],
218: [ 85000, 55000, 20000 ],
219: [ 8000, 15000, 8000 ],
401: [ 2000, 0, 0 ],
402: [ 1500, 500, 0 ],
403: [ 6000, 2000, 0 ],
404: [ 20000, 15000, 2000 ],
405: [ 5000, 3000, 0 ],
406: [ 50000, 50000, 30000 ],
407: [ 10000, 10000, 0 ],
408: [ 50000, 50000, 0 ],
502: [ 8000, 0, 2000 ],
503: [ 12500, 2500, 10000 ]
},
types: {
buildings: [ 1, 2, 3, 4, 12, 14, 15, 21, 22, 23, 24, 31, 33, 34, 36, 41, 42, 43, 44 ],
planetBuildings: [ 1, 2, 3, 4, 12, 14, 15, 21, 22, 23, 24, 31, 33, 34, 36, 44 ],
moonBuildings: [ 14, 21, 22, 23, 24, 41, 42, 43 ],
mineBuildings: [ 1, 2, 3 ],
otherBuildings: [ 4, 12, 14, 15, 21, 22, 23, 24, 31, 33, 34, 36, 41, 42, 43, 44 ],
researches: [ 106, 108, 109, 110, 111, 113, 114, 115, 117, 118, 120, 121, 122, 123, 124, 199 ],
units: [ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 401, 402, 403, 404, 405, 406, 407, 408, 502, 503 ],
ships: [ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 217, 218, 219 ],
defenses: [ 401, 402, 403, 404, 405, 406, 407, 408, 502, 503 ]
}
}
const Utils = {
reduce( ...objects ){
const result = {}
for( const object of objects ){
for( const key of Object.keys( object ) ){
const objectValueIsObject = Object( object[ key ] ) === object[ key ]
const resultValueIsObject = Object( result[ key ] ) === result[ key ]
if( objectValueIsObject && resultValueIsObject ){
result[ key ] = this.reduce( result[ key ], object[ key ] )
}else{
result[ key ] = object[ key ]
}
}
}
return result
}
}
const Lang = ( function(){
const languages = {
en: {
classes: {
alliance: {
none: 'no alliance class selected',
trader: 'Trader',
warrior: 'Warrior',
explorer: 'Researcher'
},
player: {
none: 'No player class selected',
miner: 'Collector',
warrior: 'General',
explorer: 'Discoverer'
}
},
technologies: {
1: 'Metal mine',
2: 'Crystal mine',
3: 'Deuterium synthesizer',
4: 'Solar plant',
12: 'Fusion plant',
14: 'Robotics factory',
15: 'Nanite factory',
21: 'Shipyard',
22: 'Metal storage',
23: 'Crystal storage',
24: 'Deuterium storage',
31: 'Research laboratory',
33: 'Terraformer',
34: 'Alliance depot',
36: 'Repair dock',
41: 'Moonbase',
42: 'Sensor phalanx',
43: 'Jump gate',
44: 'Missile silo',
106: 'Espionage',
108: 'Computer',
109: 'Weapons',
110: 'Shielding',
111: 'Armour',
113: 'Energy',
114: 'Hyperspace',
115: 'Combustion drive',
117: 'Impulse drive',
118: 'Hyperspace drive',
120: 'Laser',
121: 'Ion',
122: 'Plasma',
123: 'Intergalacticresearch network',
124: 'Astrophysics',
199: 'Graviton',
202: 'Small cargo',
203: 'Large cargo',
204: 'Light fighter',
205: 'Heavy fighter',
206: 'Cruiser',
207: 'Battleship ',
208: 'Colony ship',
209: 'Recycler',
210: 'Espionage probe',
211: 'Bomber',
212: 'Solar satellite',
213: 'Destroyer',
214: 'Deathstar',
215: 'Battlecruiser',
217: 'Crawler',
218: 'Reaper',
219: 'Pathfinder',
401: 'Rocket launchers',
402: 'Light lasers',
403: 'Heavy laser',
404: 'Gauss cannon',
405: 'Ion cannon',
406: 'Plasma turret',
407: 'Small shield dome',
408: 'Large shield dome',
502: 'Anti-ballistic missiles',
503: 'Interplanetary missile',
11101: 'Residential Sector',
11102: 'Biosphere Farm',
11103: 'Research Centre',
11104: 'Academy of Sciences',
11105: 'Neuro-Calibration Centre',
11106: 'High Energy Smelting',
11107: 'Food Silo',
11108: 'Fusion-Powered Production',
11109: 'Skyscraper',
11110: 'Biotech Lab',
11111: 'Metropolis',
11112: 'Planetary Shield',
11201: 'Intergalactic Envoys',
11202: 'High-Performance Extractors',
11203: 'Fusion Drives',
11204: 'Stealth Field Generator',
11205: 'Orbital Den',
11206: 'Research AI',
11207: 'High-Performance Terraformer',
11208: 'Enhanced Production Technologies',
11209: 'Light Fighter Mk II',
11210: 'Cruiser Mk II',
11211: 'Improved Lab Technology',
11212: 'Plasma Terraformer',
11213: 'Low-Temperature Drives',
11214: 'Bomber Mk II',
11215: 'Destroyer Mk II',
11216: 'Battlecruiser Mk II',
11217: 'Robot Assistants',
11218: 'Supercomputer'
},
titles: {
missing: 'Missing data',
overview: 'Points investment',
empire: ( player, universe, lang ) => `${ player }'s player account on ${ universe }.${ lang }`,
production: ( player, universe, lang ) => `Player's production ${ player.name } on ${ universe.name }.${ universe.lang }`,
generated: ( date, time ) => `Generated on ${ date } at ${ time } by `
},
alliance: 'Alliance',
crystal: 'Crystal',
daily: 'Daily',
defense: 'Defense',
defenses: 'Defenses',
destroyed: 'place(s) if destroyed',
deuterium: 'deuterium',
facilities: 'Facilities',
fleet: 'Fleet',
fleets: 'Fleets',
highscore: 'Highscore',
hint: 'There is missing data. Visit the empire view and/or the following pages',
hourly: 'Hourly',
metal: 'Metal',
mines: 'Mines',
minesPoints: 'Mines points invested',
minesProduction: 'Mines production',
moonBuildings: 'Moon buildings',
moonDefenses: 'Moon defenses',
moonFields: 'Moon fields',
noAmProduction: 'Production without AM',
notification: 'Export placed in clipboard',
others: 'Others',
otherBuildings: 'Other buildings',
planetBuildings: 'Planet buildings',
planetDefenses: 'Planet defenses',
planetFields: 'Planet fields',
production: 'Production',
productions: 'Productions',
research: 'Research',
researches: 'Researches',
resources: 'Resources',
upgraded: 'place(s) when finished',
upgrades: 'In construction',
used: 'Used',
weekly: 'Weekly'
},
fr: {
classes: {
alliance: {
none: "aucune classe d'alliance sélectionnée",
trader: 'Marchand',
warrior: 'Guerrier',
explorer: 'Chercheur'
},
player: {
none: "aucune classe de base sélectionnée",
miner: 'Collecteur',
warrior: 'Général',
explorer: 'Explorateur'
}
},
technologies: {
1: 'Mine de métal',
2: 'Mine de cristal',
3: 'Synthétiseur de deutérium',
4: 'Centrale électrique solaire',
12: 'Centrale électrique de fusion',
14: 'Usine de robots',
15: 'Usine de nanites',
21: 'Chantier spatial',
22: 'Hangar de métal',
23: 'Hangar de cristal',
24: 'Réservoir de deutérium',
31: 'Laboratoire de recherche',
33: 'Terraformeur',
34: 'Dépôt de ravitaillement',
36: 'Dock spatial',
41: 'Base lunaire',
42: 'Phalange de capteur',
43: 'Porte de saut spatial',
44: 'Silo de missiles',
106: 'Espionnage',
108: 'Ordinateur',
109: 'Armes',
110: 'Bouclier',
111: 'Protection',
113: 'Énergie',
114: 'Hyperespace',
115: 'Réacteur à combustion',
117: 'Réacteur à impulsion',
118: 'Propulsion hyperespace',
120: 'Laser',
121: 'Ions',
122: 'Plasma',
123: 'Réseau de recherche',
124: 'Astrophysique',
199: 'Graviton',
202: 'Petit transporteur',
203: 'Grand transporteur',
204: 'Chasseur léger',
205: 'Chasseur lourd',
206: 'Croiseur',
207: 'Vaisseau de bataille ',
208: 'Vaisseau de colonisation',
209: 'Recycleur',
210: "Sonde d'espionnage",
211: 'Bombardier',
212: 'Satellite solaire',
213: 'Destructeur',
214: 'Étoile de la mort',
215: 'Traqueur',
217: 'Foreuse',
218: 'Faucheur',
219: 'Éclaireur',
401: 'Lanceur de missiles',
402: 'Artillerie laser légère',
403: 'Artillerie laser lourde',
404: 'Canon de Gauss',
405: 'Artillerie à ions',
406: 'Lanceur de plasma',
407: 'Petit bouclier',
408: 'Grand bouclier',
502: "Missile d'interception",
503: 'Missile interplanétaire'
},
titles: {
missing: 'Données manquantes',
overview: 'Investissement des points',
empire: ( player, universe, lang ) => `Compte du joueur ${ player } sur ${ universe }.${ lang }`,
production: ( player, universe, lang ) => `Production du joueur ${ player.name } sur ${ universe.name }.${ universe.lang }`,
generated: ( date, time ) => `Généré le ${ date } à ${ time } par `
},
alliance: 'Alliance',
crystal: 'Cristal',
daily: 'Journalière',
defense: 'Défense',
defenses: 'Défenses',
destroyed: 'place(s) si détruit',
deuterium: 'Deutérium',
facilities: 'Installations',
fleet: 'Flotte',
fleets: 'Flottes',
highscore: 'Classement',
hint: 'Il manque des données. Visitez la vue empire et/ou les pages suivantes',
hourly: 'Horaire',
metal: 'Métal',
mines: 'Mines',
minesPoints: 'Points investis en mines',
minesProduction: 'Production des mines',
moonBuildings: 'Bâtiments lunaires',
moonDefenses: 'Défenses lunaires',
moonFields: 'Cases lunaires',
noAmProduction: 'Production sans AM',
notification: 'Export placé dans le presse-papier',
others: 'Autres',
otherBuildings: 'Autres bâtiments',
planetBuildings: 'Bâtiments planétaires',
planetDefenses: 'Défenses planétaires',
planetFields: 'Cases planétaires',
production: 'Production',
productions: 'Productions',
research: 'Recherche',
researches: 'Recherches',
resources: 'Ressources',
upgraded: 'place(s) quand terminé',
upgrades: 'En construction',
used: 'Utilisé',
weekly: 'Hebdomadaire'
}
}
return languages[ document.documentElement.lang ] || languages.en
} )()
const StorageData = ( function(){
const key = 'InfoCompte-9'
let item
let id
return {
get(){
item = JSON.parse( localStorage.getItem( key ) ) || {}
id = document.head.querySelector( 'meta[name=ogame-player-name]' ).content
return item[ id ] ||= {}
},
set( value ){
item[ id ] = value
localStorage.setItem( key, JSON.stringify( item ) )
}
}
} )()
const PageData = ( function(){
function parseNumber( string ){
return parseInt( string.replace( /\./g, '' ) )
}
function elementExists( selector ){
return new Promise( function( resolve ){
const observer = new MutationObserver( function(){
const element = document.querySelector( selector )
if( element ){
observer.disconnect()
resolve( element )
}
} )
observer.observe( document.body, { childList: true, subtree: true } )
} )
}
function getMetaData(){
const elements = document.head
return {
universe: {
lang: elements.querySelector( 'meta[name=ogame-language]' ).content,
name: elements.querySelector( 'meta[name=ogame-universe-name]' ).content,
speeds: {
economy: parseInt( elements.querySelector( 'meta[name=ogame-universe-speed]' ).content )
}
},
player: {
name: elements.querySelector( 'meta[name=ogame-player-name]' ).content
}
}
}
async function getEmpirePageData(){
function getPositionsData(){
function getBuildingsTechnologies( element ){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const { childNodes, classList } of element.querySelectorAll( '.supply > div, .station > div' ) ){
const id = parseInt( classList[ 0 ] )
let [ stock, , target = 0 ] = childNodes
stock = parseNumber( stock.textContent )
target &&= parseNumber( target.textContent )
currents[ id ] = upgraded[ id ] = stock
upgrades[ id ] = 0
if( stock < target ){
upgraded[ id ] = target
upgrades[ id ] = 1
}
}
return { currents, upgrades, upgraded }
}
function getUnitsTechnologies( element ){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const { childNodes, classList } of element.querySelectorAll( '.ships > div, .defence > div' ) ){
const id = parseInt( classList[ 0 ] )
let [ value, , active = 0 ] = childNodes
value = parseNumber( value.textContent )
active &&= parseNumber( active.textContent )
currents[ id ] = upgraded[ id ] = value
upgrades[ id ] = 0
if( active ){
upgraded[ id ] = value + active
upgrades[ id ] = active
}
}
return { currents, upgrades, upgraded }
}
const type = document.querySelector( '#planetsTab.active' ) ? 'P' : 'M'
const result = {}
for( const element of document.querySelectorAll( '.planet:not( .summary )' ) ){
const coordinates = element.querySelector( '.planetData :first-child li:first-child' ).textContent.slice( 1, -1 )
result[ `${ coordinates }:${ type }` ] = {
technologies: Utils.reduce( getBuildingsTechnologies( element ), getUnitsTechnologies( element ) )
}
}
return { player: { positions: result } }
}
function getResearchesTechnologies(){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const { childNodes, classList } of document.querySelectorAll( '.planet:first-child .research > div' ) ){
const id = parseInt( classList[ 0 ] )
let [ value, , active ] = childNodes
value = parseInt( value.textContent )
active &&= parseInt( active.textContent )
currents[ id ] = upgraded[ id ] = value
upgrades[ id ] = 0
if( active ){
upgraded[ id ] = active
upgrades[ id ] = 1
}
}
return { player: { researches: { currents, upgrades, upgraded } } }
}
return Utils.reduce( getMetaData(), getPositionsData(), getResearchesTechnologies() )
}
async function getOtherPageData(){
function getCommonPageData(){
function getClassData(){
const list = document.querySelector( '#characterclass div' ).classList
let result = null
for( const key of [ 'miner', 'warrior', 'explorer' ] ){
if( list.contains( key ) ){
result = key
break
}
}
return result
}
function getOfficersData(){
const result = {}
for( const key of [ 'commander', 'admiral', 'engineer', 'geologist', 'technocrat' ] ){
const element = document.querySelector( `#officers a.on.${ key }` )
result[ key ] = element ? true : false
}
return result
}
function getPositionsData(){
function getID( string ){
const [ result ] = string.match( /(?<=cp=)\d+/ )
return parseInt( result )
}
function getName( string ){
const [ result ] = string.split( ' [' )
return result
}
function getCoordinates( string ){
const [ , result ] = string.split( /\[(.+)\]/ )
return result
}
function getFields( string ){
const [ , result ] = string.split( /\((.+)\)/ )
const [ used, count ] = result.split( '/' )
return { count: parseInt( count ), used: parseInt( used ) }
}
function getTemperatures( string ){
const result = {}
if( string.includes( '°' ) ){
const [ , min, , max ] = string.replace( /\s/g, '' ).split( /(-?\d+)(?=°)/ )
result.min = parseInt( min )
result.max = parseInt( max )
}
return result
}
const elements = document.querySelectorAll( '#planetList .smallplanet :is( a.planetlink, a.moonlink )' )
const template = document.createElement( 'template' )
const result = {}
for( const { classList, title } of elements ){
template.innerHTML = title
const text = template.content.textContent
const coordinates = getCoordinates( text )
const type = classList.contains( 'planetlink' ) ? 'P' : 'M'
result[ `${ coordinates }:${ type }` ] = {
id: getID( title ),
name: getName( text ),
fields: getFields( text ),
temperatures: getTemperatures( text )
}
}
return result
}
const result = {
player: {
class: getClassData(),
officers: getOfficersData(),
positions: getPositionsData()
}
}
return Utils.reduce( getMetaData(), result )
}
async function getSpecificPageData(){
function getPositionKey(){
const element = document.head
const coordinates = element.querySelector( 'meta[name=ogame-planet-coordinates]' ).content
const type = element.querySelector( 'meta[name=ogame-planet-type]' ).content
return `${ coordinates }:${ type.charAt( 0 ).toUpperCase() }`
}
async function getAllianceData(){
let result = 'none'
if( document.querySelector( '#applicationTab' ) ){
await elementExists( '#allyData' )
const list = document.querySelector( '.alliance_class' ).classList
for( const key of [ 'trader', 'warrior', 'explorer' ] ){
if( list.contains( key ) ){
result = key
break
}
}
}
return { class: result }
}
function getHighscoreData(){
const ranks = {}
let rank = {}
for( const element of document.querySelectorAll( '#ranks tr' ) ){
const position = parseInt( element.querySelector( '.position' ).textContent )
const score = parseNumber( element.querySelector( '.score' ).textContent )
if( position && score ){
if( element.classList.contains( 'myrank' ) ) rank = { position, score }
else ranks[ position ] = score
}
}
return { rank, ranks }
}
function getBuildingsTechnologies(){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const element of document.querySelectorAll( '#technologies > ul > li' ) ){
const value = element.querySelector( '.level' )?.getAttribute( 'data-value' )
if( value ){
const id = parseInt( element.getAttribute( 'data-technology' ) )
currents[ id ] = upgraded[ id ] = parseInt( value )
upgrades[ id ] = 0
}
}
const active = document.querySelector( '.technology[data-status=active]' )
if( active ){
const stock = parseInt( active.querySelector( '.stockAmount' ).textContent )
const target = parseInt( active.querySelector( '.targetlevel' ).textContent )
if( stock < target ){
const id = parseInt( active.getAttribute( 'data-technology' ) )
upgraded[ id ] = target
upgrades[ id ] = 1
}
}
return { currents, upgraded, upgrades }
}
function getUnitsTechnologies(){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const element of document.querySelectorAll( '#technologies ul > li' ) ){
const id = parseInt( element.getAttribute( 'data-technology' ) )
const value = parseInt( element.querySelector( '.amount' ).getAttribute( 'data-value' ) )
currents[ id ] = upgraded[ id ] = value
upgrades[ id ] = 0
}
for( const element of document.querySelectorAll( 'td.first, .queue td' ) ){
const id = parseInt( element.querySelector( 'img' ).alt.substring( 7 ) )
const value = parseNumber( element.textContent )
upgraded[ id ] += value
upgrades[ id ] = value
}
return { currents, upgrades, upgraded }
}
function getResearchesTechnologies(){
const currents = {}
const upgraded = {}
const upgrades = {}
for( const technology of document.querySelectorAll( '#technologies ul > li' ) ){
const id = parseInt( technology.getAttribute( 'data-technology' ) )
const value = parseInt( technology.querySelector( '.level' ).getAttribute( 'data-value' ) )
currents[ id ] = upgraded[ id ] = value
upgrades[ id ] = 0
}
const active = document.querySelector( '.technology[data-status=active]' )
if( active ){
const id = parseInt( active.getAttribute( 'data-technology' ) )
upgraded[ id ] = parseInt( active.querySelector( '.targetlevel' ).textContent )
upgrades[ id ] = 1
}
return { currents, upgrades, upgraded }
}
function getProductions(){
function getValueFromElementText(selector){
return parseNumber(table.querySelector(selector).innerText)
}
function getValueFromElementTitle(selector){
return parseNumber(table.querySelector(selector).title)
}
const table = document.querySelector( '.listOfResourceSettingsPerPlanet' )
const geologist = document.querySelector( `#officers a.on.geologist` )
const crawlersRate = geologist ? .9 : 1
return {
basic: {
metal: getValueFromElementText( ':nth-child( 3 ) > :nth-child( 2 )' ),
crystal: getValueFromElementText( ':nth-child( 3 ) > :nth-child( 3 )' )
},
mines: {
metal: getValueFromElementTitle( ':nth-child( 4 ) > :nth-child( 3 ) > span' ),
crystal: getValueFromElementTitle( ':nth-child( 5 ) > :nth-child( 4 ) > span' ),
deuterium: getValueFromElementTitle( ':nth-child( 6 ) > :nth-child( 5 ) > span' )
},
fusion: {
deuterium: getValueFromElementText( ':nth-child( 8 ) > :nth-child( 5 )' ) * -1
},
crawlers: {
metal: Math.round( getValueFromElementText( ':nth-child( 10 ) > :nth-child( 3 )' ) * crawlersRate ),
crystal: Math.round( getValueFromElementText( ':nth-child( 10 ) > :nth-child( 4 )' ) * crawlersRate ),
deuterium: Math.round( getValueFromElementText( ':nth-child( 10 ) > :nth-child( 5 )' ) * crawlersRate )
},
plasma: {
metal: getValueFromElementText( ':nth-child( 11 ) > :nth-child( 3 )' ),
crystal: getValueFromElementText( ':nth-child( 11 ) > :nth-child( 4 )' ),
deuterium: getValueFromElementText( ':nth-child( 11 ) > :nth-child( 5 )' )
},
classes: {
alliance: {
metal: getValueFromElementText( ':nth-child( 17 ) > :nth-child( 3 )' ),
crystal: getValueFromElementText( ':nth-child( 17 ) > :nth-child( 4 )' ),
deuterium: getValueFromElementText( ':nth-child( 17 ) > :nth-child( 5 )' )
},
player: {
metal: getValueFromElementText( ':nth-child( 16 ) > :nth-child( 3 )' ),
crystal: getValueFromElementText( ':nth-child( 16 ) > :nth-child( 4 )' ),
deuterium: getValueFromElementText( ':nth-child( 16 ) > :nth-child( 5 )' )
}
}
}
}
const result = {}
switch( currentPage ){
case 'supplies':
case 'facilities':
result.player = {
positions: {
[ getPositionKey() ]: {
technologies: getBuildingsTechnologies()
}
}
}
break
case 'resourceSettings':
result.player = {
positions: {
[ getPositionKey() ]: {
productions: getProductions()
}
}
}
break
case 'shipyard':
case 'defenses':
result.player = {
positions: {
[ getPositionKey() ]: {
technologies: getUnitsTechnologies()
}
}
}
break
case 'research':
result.player = {
researches: getResearchesTechnologies()
}
break
case 'alliance':
result.player = {
alliance: await getAllianceData()
}
break
case 'highscore':
result.universe = {
highscore: getHighscoreData()
}
break
}
return result
}
return Utils.reduce( getCommonPageData(), await getSpecificPageData() )
}
return {
async get(){
if( currentPage === 'empire' ) return await getEmpirePageData()
else return await getOtherPageData()
}
}
} )()
const PageComponent = ( function(){
function getAsNumber( value ){
return isNaN( value ) ? parseInt( value.match( /\d+/ )[ 0 ] ) : value
}
function getAsLocaleString( value ){
return value.toLocaleString( 'de-DE' )
}
function getAsPaddedString( value, targetLength, padString ){
return value.toString().padStart( targetLength, padString )
}
function getAsPercentage( value ){
const result = Math.round( value * 10000 ) * .01
return result.toFixed( 2 ).padStart( 5, '0' ).replace( '.', ',' ) + ' %'
}
function getBuildingResources( id, level ){
const [ metal, crystal, deuterium, factor ] = GameData.costs[ id ]
return Math.floor( metal * factor ** ( level - 1 ) )
+ Math.floor( crystal * factor ** ( level - 1 ) )
+ Math.floor( deuterium * factor ** ( level - 1 ) )
}
function getCumulativeBuildingResources( id, level ){
let result = 0
for( let i = 1; i <= level; i++ ) result += getBuildingResources( id, i )
return result
}
function getResearchResources( id, level ){
const [ metal, crystal, deuterium, factor ] = GameData.costs[ id ]
return Math.round( metal * factor ** ( level - 1 ) * .01 ) * 100
+ Math.round( crystal * factor ** ( level - 1 ) * .01 ) * 100
+ Math.round( deuterium * factor ** ( level - 1 ) * .01 ) * 100
}
function getCumulativeResearchResources( id, level ){
let result = 0
for( let i = 1; i <= level; i++ ) result += getResearchResources( id, i )
return result
}
function getUnitsResources( id, amount ){
const [ metal, crystal, deuterium ] = GameData.costs[ id ]
return metal * amount + crystal * amount + deuterium * amount
}
function getMetalMineProduction( level, position, speed ){
const rate = GameData.bonuses.positions.metal[ position - 1 ]
return Math.floor( 30 * level * 1.1 ** level * rate * speed )
}
function getCrystalMineProduction( level, position, speed ){
const rate = GameData.bonuses.positions.metal[ position - 1 ]
return Math.floor( 20 * level * 1.1 ** level * rate * speed )
}
function getDeuteriumMineProduction( level, temperature, speed ){
return Math.floor( 10 * level * 1.1 ** level * ( 1.44 - .004 * temperature ) * speed )
}
function getMetalPlasmaProduction( production, level ){
return Math.round( production * level * .01 )
}
function getCrystalPlasmaProduction( production, level ){
return Math.round( production * level * .0066 )
}
function getDeuteriumPlasmaProduction( production, level ){
return Math.round( production * level * .0033 )
}
const SharedStyles = {
// OGame's positionning fix
common: `
#productionboxBottom {
position: initial;
}
#ic-component {
all: inherit;
background: #0d1014;
border: 2px solid #000;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 8px;
line-height: 1;
margin: 0 7px 24px;
padding: 0 8px 8px;
position: relative;
width: 654px;
}
#ic-component::before, #infocompte::after {
content: "";
left: -9px;
position: absolute;
width: 668px;
}
#ic-component::before {
background: url( "//gf3.geo.gfsrv.net/cdn53/f333e15eb738b8ec692340f507e1ae.png" ) bottom left no-repeat, url( "//gf2.geo.gfsrv.net/cdnd5/66551209db14e23b3001901b996cc6.png" ) bottom right no-repeat;
height: 28px;
top: -3px;
}
#ic-component::after {
background: url( "//gf3.geo.gfsrv.net/cdnea/0330abcdca0d125d35a0ebace4b584.png" ) bottom left no-repeat, url( "//gf1.geo.gfsrv.net/cdn9b/8003a40825bc96919c5fec01b018b8.png" ) bottom right no-repeat;
bottom: -4px;
height: 50px;
z-index: -1;
}
#ic-title {
background: url( "//gf1.geo.gfsrv.net/cdnfb/a4e7913209228ebaf2297429aeb87b.png" );
color: #6f9fc8;
font: bold 12px/27px Verdana,Arial,Helvetica,sans-serif;
position: relative;
text-align: center;
}
#ic-title::before, #ic-title::after {
content: "";
height: 27px;
position: absolute;
top: 0;
width: 26px;
}
#ic-title::before {
background: url( "//gf2.geo.gfsrv.net/cdn4a/127bd495b9325216af08a588ecc540.png" );
left: -5px;
}
#ic-title::after {
background: url( "//gf2.geo.gfsrv.net/cdn1d/80db96934a5b82ce002f839cd85a44.png" );
right: -5px;
}`
}
const MissingDataComponent = ( function(){
function getComponentData( { player, universe } ){
const { positions, researches, alliance } = player
const { highscore } = universe
const result = {
supplies: [],
productions: [],
facilities: [],
shipyard: [],
defenses: [],
research: true,
alliance: true,
highscore: true
}
for( const [ key, position ] of Object.entries( positions ) ){
const { id, name, technologies, productions } = position
if( !technologies || !( 22 in technologies.currents ) ) result.supplies.push( [ id, name ] )
if( !technologies || !( 14 in technologies.currents ) ) result.facilities.push( [ id, name ] )
if( !technologies || !( 202 in technologies.currents ) ) result.shipyard.push( [ id, name ] )
if( !technologies || !( 401 in technologies.currents ) ) result.defenses.push( [ id, name ] )
if( key.endsWith( 'P' ) && !productions ) result.productions.push( [ id, name ] )
}
if( !result.supplies.length ) delete result.supplies
if( !result.productions.length ) delete result.productions
if( !result.facilities.length ) delete result.facilities
if( !result.shipyard.length ) delete result.shipyard
if( !result.defenses.length ) delete result.defenses
if( highscore ) delete result.highscore
if( researches ) delete result.research
if( alliance ) delete result.alliance
return Object.keys( result ).length ? result : null
}
function getStyle(){
return `${ SharedStyles.common }
#ic-title {
margin-bottom: 8px;
}
#ic-component h4 {
color: #677e98;
font-size: 16px;
font-weight: 700;
margin-top: 8px;
}
#ic-component p {
line-height: 1.5;
}`
}
function getTemplate( data ){
let result = `<p>${ Lang.hint } :</p>`
if( data.supplies ){
const links = data.supplies.map( ( [ id, key ] ) => `<a href=?page=ingame&component=supplies&cp=${ id }>${ key }</a>` )
result += `<h4>${ Lang.resources }</h4><p>${ links.join( ', ' ) }.</p>`
}
if( data.productions ){
const links = data.productions.map( ( [ id, key ] ) => `<a href=?page=resourceSettings&cp=${ id }>${ key }</a>` )
result += `<h4>${ Lang.productions }</h4><p>${ links.join( ', ' ) }.</p>`
}
if( data.facilities ){
const links = data.facilities.map( ( [ id, key ] ) => `<a href=?page=ingame&component=facilities&cp=${ id }>${ key }</a>` )
result += `<h4>${ Lang.facilities }</h4><p>${ links.join( ', ' ) }.</p>`
}
if( data.shipyard ){
const links = data.shipyard.map( ( [ id, key ] ) => `<a href=?page=ingame&component=shipyard&cp=${ id }>${ key }</a>` )
result += `<h4>${ Lang.fleets }</h4><p>${ links.join( ', ' ) }.</p>`
}
if( data.defenses ){
const links = data.defenses.map( ( [ id, key ] ) => `<a href=?page=ingame&component=defenses&cp=${ id }>${ key }</a>` )
result += `<h4>${ Lang.defenses }</h4><p>${ links.join( ', ' ) }.</p>`
}
if( data.highscore || data.research || data.alliance ){
const links = []
if( data.highscore ) links.push( `<a href=${ document.querySelector( '#bar li:nth-child(2) a' ).href }>${ Lang.highscore }</a>`)
if( data.research ) links.push( `<a href=?page=ingame&component=research>${ Lang.research }</a>` )
if( data.alliance ) links.push( `<a href=?page=ingame&component=alliance>${ Lang.alliance }</a>` )
result += `<h4>${ Lang.others }</h4><p>${ links.join( ', ' ) }.</p>`
}
return `<div id="ic-component">
<h3 id="ic-title">${ Lang.titles.missing }</h3>
${ result }
</div>`
}
return {
init( data ){
const missing = getComponentData( data )
if( missing && currentPage === 'overview' ){
const style = document.createElement( 'style' )
const template = document.createElement( 'template' )
style.innerHTML = getStyle()
template.innerHTML = getTemplate( missing )
document.head.appendChild( style )
document.querySelector( '#middle' ).appendChild( template.content )
}
return missing ? true : false
}
}
} )()
const OverviewComponent = ( function(){
function getComponentData( { player, universe } ){
function getPoints( player, universe ){
function getCounts( player, universe ){
function getMineBuildingsPoints( { positions } ){
let metal = 0
let crystal = 0
let deuterium = 0
for( const { technologies: { currents } } of Object.values( positions ) ){
metal += getCumulativeBuildingResources( 1, currents[ 1 ] )
crystal += getCumulativeBuildingResources( 2, currents[ 2 ] )
deuterium += getCumulativeBuildingResources( 3, currents[ 3 ] )
}
const m = Math.floor( metal * .001 )
const c = Math.floor( crystal * .001 )
const d = Math.floor( deuterium * .001 )
return { metal: m, crystal: c, deuterium: d, total: Math.floor((metal + crystal + deuterium)*.001) }
}
function getOtherBuildingsPoints( { positions } ){
let result = 0
for( const { technologies: { currents } } of Object.values( positions ) ){
for( const id of GameData.types.otherBuildings ){
result += getCumulativeBuildingResources( id, currents[ id ] )
}
}
return Math.floor( result * .001 )
}
function getMoonBuildingsPoints( { positions } ){
let result = 0
for( const [ key, { technologies: { currents } } ] of Object.entries( positions ) ){
if( key.endsWith( 'M' ) ){
for( const id of GameData.types.moonBuildings ){
result += getCumulativeBuildingResources( id, currents[ id ] )
}
}
}
return Math.floor( result * .001 )
}
function getDefensePoints( { positions } ){
let result = 0
for( const { technologies: { currents } } of Object.values( positions ) ){
for( const id of GameData.types.defenses ){
result += getUnitsResources( id, currents[ id ] )
}
}
return Math.floor( result * .001 )
}
function getResearchesPoints( { researches } ){
let result = 0
for( const id of GameData.types.researches ){
result += getCumulativeResearchResources( id, researches.currents[ id ] )
}
return Math.floor( result * .001 )
}
function getUpgradePoints( { positions, researches } ){
function getUpgradeBuildingsResources( positions ){
let result = 0
for( const { technologies: { upgraded, upgrades } } of Object.values( positions ) ){
for( const id of GameData.types.buildings ){
if( upgrades[ id ] ){
result += getBuildingResources( id, upgraded[ id ] )
}
}
}
return result
}
function getUpgradeUnitsResources( positions ){
let result = 0
for( const { technologies: { upgraded, upgrades } } of Object.values( positions ) ){
for( const id of GameData.types.units ){
if( upgrades[ id ] ){
result += getUnitsResources( id, upgrades[ id ] )
}
}
}
return result
}
function getUpgradeResearchesResources( researches ){
let result = 0
for( const id of GameData.types.researches ){
if( researches.upgrades[ id ] ){
result = getResearchResources( id, researches.upgraded[ id ] )
}
}
return result
}
let result = getUpgradeBuildingsResources( positions )
result += getUpgradeUnitsResources( positions )
result += getUpgradeResearchesResources( researches )
return Math.floor( result * .001 )
}
const total = universe.highscore.rank.score,
mineBuildings = getMineBuildingsPoints( player ),
otherBuildings = getOtherBuildingsPoints( player ),
researches = getResearchesPoints( player ),
defense = getDefensePoints( player ),
fleet = total - mineBuildings.total - otherBuildings - researches - defense,
upgrades = getUpgradePoints( player ),
indestructibles = total - defense - fleet - getMoonBuildingsPoints( player )
return { total, mineBuildings, otherBuildings, researches, fleet, defense, upgrades, indestructibles }
}
function getPercentages( counts ){
return {
mineBuildings: counts.mineBuildings.total / counts.total,
otherBuildings: counts.otherBuildings / counts.total,
researches: counts.researches / counts.total,
fleet: counts.fleet / counts.total,
defense: counts.defense / counts.total,
upgrades: counts.upgrades / counts.total,
indestructibles: counts.indestructibles / counts.total
}
}
const counts = getCounts( player, universe )
const percentages = getPercentages( counts )
return { counts, percentages }
}
function getRanks( universe, points ){
const { score, position } = universe.highscore.rank
let destructed = score - ( score - points.counts.indestructibles )
let upgraded = score + points.counts.upgrades
for( const [ key, value ] of Object.entries( universe.highscore.ranks ) ){
if( value < destructed ){
destructed = key - 1 - position
break
}
}
for( const [ key, value ] of Object.entries( universe.highscore.ranks ) ){
if( value < upgraded ){
upgraded = Math.max( 0, position - key )
break
}
}
return { destructed, upgraded }
}
function getChart( { percentages } ){
function getCicle( color, percentage, angle ){
const offset = 2 * Math.PI * 42
const length = offset - offset * percentage
const rotation = angle * 360 - 90
return `<circle fill=transparent
stroke=${ color }
stroke-width=16
stroke-dasharray=${ offset }
stroke-dashoffset=${ length }
cx=50
cy=50
r=42
transform="rotate( ${ rotation } 50 50 )"/>`
}
const colors = [ '#eb782d', '#9c3d00', '#0077b6', '#e30613', '#16bd05' ]
const { mineBuildings, otherBuildings, researches, fleet, defense } = percentages
let offset = 0
let result = ''
for( const [ index, percentage ] of Object.entries( [ mineBuildings, otherBuildings, researches, fleet, defense ] ) ){
result += getCicle( colors[ index ], percentage, offset )
offset += percentage
}
return result
}
function getProductions( player, universe ){
function getMinesProduction( { positions } ){
let metal = 0
let crystal = 0
let deuterium = 0
for( const { productions } of Object.values( positions ) ){
if( productions ){
metal += productions.mines.metal
crystal += productions.mines.crystal
deuterium += productions.mines.deuterium
}
}
return {
hourly: { metal, crystal, deuterium },
daily: { metal: metal * 24, crystal: crystal * 24, deuterium: deuterium * 24 },
weekly: { metal: metal * 168, crystal: crystal * 168, deuterium: deuterium * 168 }
}
}
function getTotalProduction( { positions } ){
let metal = 0
let crystal = 0
let deuterium = 0
for( const { productions } of Object.values( positions ) ){
if( productions ){
const { basic, mines, fusion, crawlers, plasma, classes: { alliance, player } } = productions
metal += basic.metal + mines.metal + crawlers.metal + plasma.metal + alliance.metal + player.metal
crystal += basic.crystal + mines.crystal + crawlers.crystal + plasma.crystal + alliance.crystal + player.crystal
deuterium += mines.deuterium + fusion.deuterium + crawlers.deuterium + plasma.deuterium + alliance.deuterium + player.deuterium
}
}
return {
hourly: { metal, crystal, deuterium },
daily: { metal: metal * 24, crystal: crystal * 24, deuterium: deuterium * 24 },
weekly: { metal: metal * 168, crystal: crystal * 168, deuterium: deuterium * 168 }
}
}
return {
mines: getMinesProduction( player ),
total: getTotalProduction( player )
}
}
const points = getPoints( player, universe )
const productions = getProductions( player, universe )
const ranks = getRanks( universe, points )
const chart = getChart( points )
return { points, productions, ranks, chart }
}
function getStyle(){
return `${ SharedStyles.common }
.ic-flex-container {
display: flex;
}
#ic-main-container {
border: 1px solid black;
}
#ic-footer-container {
color: grey;
justify-content: space-between;
padding: 0 1px;
}
#ic-export-container {
gap: 8px;
justify-content: start;
}
#ic-notification {
align-items: center;
display: none;
height: 35.333px;
margin-left: 8px;
}
#ic-notification::before{
content: '✓';
margin-right: 6px;
}
#ic-link-container {
align-items: center;
gap: 8px;
}
#ic-component table {
color: grey;
flex: auto;
}
#ic-component tr {
display: flex;
justify-content: space-between;
padding: 8px;
}
#ic-component tr:nth-child( odd ) {
background-color: #12171C;
}
#ic-component td > div {
text-align: right;
}
#ic-component td > div:not( :last-child ) {
margin-bottom: 8px;
}
.ic-marked-cell::before {
color: transparent;
content: '⬤';
margin-right: 6px;
}
#ic-mines-cell::before {
color: #eb782d;
}
#ic-buildings-cell::before {
color: #9c3d00;
}
#ic-researches-cell::before {
color: #0077b6;
}
#ic-fleet-cell::before {
color: #e30613;
}
#ic-defense-cell::before {
color: #16BD05;
}
#ic-chart {
height: 188px;
margin: 24px;
}
#ic-component button {
background: linear-gradient(to bottom, #2D3743 0%, #181E25 100%);
border: 1px solid black;
border-color: #28323E #222B34 #232A34 #222B34;
border-radius: 3px;
box-shadow: 0 1px 3px 0 black, inset 0 1px 1px 0 hsl(213, 22%, 32%);
color: grey;
padding: 8px 12px;
}
#ic-component button::before {
content: '⭳';
font-weight: bolder;
margin-right: 6px;
}
#ic-component button:hover, #infocompte input:hover {
cursor: pointer;
}
#ic-component label {
align-items: center;
display: flex;
}
#ic-component input {
margin-right: 6px;
}`
}
function getTemplate( data ){
const { points, ranks, chart } = data.component
const { counts, percentages } = points
return `<div id="ic-component">
<h3 id="ic-title">${ Lang.titles.overview }</h3>
<div id= "ic-main-container" class="ic-flex-container">
<table>
<tr>
<td id="ic-mines-cell" class="ic-marked-cell">${ Lang.mines }</td>
<td><span>${ getAsLocaleString( counts.mineBuildings.total ) }</span> · <span>${ getAsPercentage( percentages.mineBuildings ) }</span></td>
</tr>
<tr>
<td id="ic-buildings-cell" class="ic-marked-cell">${ Lang.otherBuildings }</td>
<td><span>${ getAsLocaleString( counts.otherBuildings ) }</span> · <span>${ getAsPercentage( percentages.otherBuildings ) }</span></td>
</tr>
<tr>
<td id="ic-researches-cell" class="ic-marked-cell">${ Lang.researches }</td>
<td><span>${ getAsLocaleString( counts.researches ) }</span> · <span>${ getAsPercentage( percentages.researches ) }</span></td>
</tr>
<tr>
<td id="ic-fleet-cell" class="ic-marked-cell">${ Lang.fleet }</td>
<td><span>${ getAsLocaleString( counts.fleet ) }</span> · <span>${ getAsPercentage( percentages.fleet ) }</span></td>
</tr>
<tr>
<td id="ic-defense-cell" class="ic-marked-cell">${ Lang.defense }</td>
<td><span>${ getAsLocaleString( counts.defense ) }</span> · <span>${ getAsPercentage( percentages.defense ) }</span></td>
</tr>
<tr>
<td class="ic-marked-cell">Indestructibles</td>
<td>
<div><span>${ getAsLocaleString( counts.indestructibles ) }</span> · <span>${ getAsPercentage( percentages.indestructibles ) }</span></div>
<div>- ${ ranks.destructed } ${ Lang.destroyed }</div>
</td>
</tr>
<tr>
<td class="ic-marked-cell">${ Lang.upgrades }</td>
<td>
<div><span>${ getAsLocaleString( counts.upgrades ) }</span> · <span>${ getAsPercentage( percentages.upgrades ) }</span></div>
<div>+ ${ ranks.upgraded } ${ Lang.upgraded }</div>
</td>
</tr>
</table>
<svg id="ic-chart" viewBox="0 0 100 100">${ chart }</svg>
</div>
<div id="ic-footer-container" class="ic-flex-container">
<div id="ic-export-container" class="ic-flex-container">
<button id="ic-empire-export-button">Empire</button>
<button id="ic-production-export-button">Production</button>
<label><input type="checkbox" checked>BBCode</label>
</div>
<div id="ic-notification">${ Lang.notification }</div>
<div id="ic-link-container" class="ic-flex-container">
<a href="https://board.fr.ogame.gameforge.com/index.php?thread/746302-infocompte/" target="_blank">InfoCompte ${ GM_info.script.version }</a>
<span>·</span>
<a href="https://ko-fi.com/A0A4DEZRA" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="24" height="24">
<path fill="#fff" d="M43.8 17.3h3.1a11 11 0 0 1 11 11v.7a11 11 0 0 1-11 11h-3.1v3.3a5 5 0 0 1-5.1 5.1h-24a5 5 0 0 1-5.1-5V19.7a2.5 2.5 0 0 1 2.5-2.5Zm0 5.9v11h2.8a5.5 5.5 0 0 0 0-11Z"/>
<path fill="#f15f5e" d="M26 27.7c.8-2.3 2.6-3.5 5.6-3.5 4.4 0 6 5.5 3.7 9.1q-2.3 3.6-9.3 9-7-5.4-9.3-9c-2.3-3.6-.7-9 3.7-9q4.4 0 5.6 3.4Z"/>
</svg>
</a>
</div>
</div>
</div>`
}
const Listeners = ( function(){
async function animate(){
const container = document.querySelector( '#ic-export-container' )
const notification = document.querySelector( '#ic-notification' )
await container.animate( { opacity: 0 }, 500 ).finished
container.style.display = 'none'
notification.style.display = 'flex'
await notification.animate( { opacity: [ 0, 1 ] }, 500 ).finished
await notification.animate( { opacity: [ 1, 0 ] }, { delay: 1500, duration: 500 } ).finished
notification.style.display = 'none'
container.style.display = 'flex'
container.animate( { opacity: [ 0, 1 ] }, 500 ).finished
}
function formate( text ){
if( !document.querySelector( '#ic-export-container input' ).checked ){
text = text.replace( /\[\/?[^\]]*\]/g, '' )
}
return text
}
return {
getEmpire(){
const result = formate( Exports.getEmpire( data ) )
navigator.clipboard.writeText( result )
animate()
},
getProduction(){
const result = formate( Exports.getProduction( data ) )
navigator.clipboard.writeText( result )
animate()
}
}
} )()
return {
init( data ){
const style = document.createElement( 'style' )
const template = document.createElement( 'template' )
data.component = getComponentData( data )
style.innerHTML = getStyle()
template.innerHTML = getTemplate( data )
document.head.appendChild( style )
document.querySelector( '#middle' ).appendChild( template.content )
document.querySelector( '#ic-empire-export-button' ).addEventListener( 'click', Listeners.getEmpire )
document.querySelector( '#ic-production-export-button' ).addEventListener( 'click', Listeners.getProduction )
}
}
} )()
const Exports = ( function(){
function getDate(){
const date = new Date()
return [ date.toLocaleDateString( 'fr-FR' ), date.toLocaleTimeString( 'de-DE', { timeStyle: 'short'} ) ]
}
function getTechnologyResume( array ){
const list = array.map( element => `[color=#9dc2e1]${ getAsLocaleString( element ) }[/color]` ).join( ', ' )
const average = array.reduce( ( previous, current ) => previous + getAsNumber( current ), 0 ) / array.length
return `${ list } · ø ${ getAsLocaleString( Math.round( average * 10 ) / 10 ) }`
}
return {
getEmpire( { player, universe, component } ){
const { counts, percentages } = component.points
const { mines, total } = component.productions
const [ date, time ] = getDate()
return `[size=18]${ Lang.titles.empire( player.name, universe.name, universe.lang ) }[/size]
[size=8]${ Lang.titles.generated( date, time ) } [url=https://board.fr.ogame.gameforge.com/index.php?thread/746302-infocompte/]InfoCompte ${ GM_info.script.version }[/url][/size]
${ Lang.classes.player[ player.class ] } & ${ Lang.classes.alliance[ player.alliance.class ] }
[color=#6f9fc8]POINTS[/color]
${ Lang.mines } : [color=#9dc2e1]${ getAsLocaleString( counts.mineBuildings.total ) }[/color] · ${ getAsPercentage( percentages.mineBuildings ) }
${ Lang.otherBuildings } : [color=#9dc2e1]${ getAsLocaleString( counts.otherBuildings ) }[/color] · ${ getAsPercentage( percentages.otherBuildings ) }
${ Lang.researches } : [color=#9dc2e1]${ getAsLocaleString( counts.researches ) }[/color] · ${ getAsPercentage( percentages.researches ) }
${ Lang.fleet } : [color=#9dc2e1]${ getAsLocaleString( counts.fleet ) }[/color] · ${ getAsPercentage( percentages.fleet ) }
${ Lang.defense } : [color=#9dc2e1]${ getAsLocaleString( counts.defense ) }[/color] · ${ getAsPercentage( percentages.defense ) }
Total : [color=#9dc2e1]${ getAsLocaleString( counts.total ) }[/color] · ${ getAsPercentage( percentages.indestructibles ) } indestructible
[color=#6f9fc8]${ Lang.production.toUpperCase() }[/color]
${ Lang.metal } : [color=#9dc2e1]${ getAsLocaleString( total.daily.metal ) }[/color]
${ Lang.crystal } : [color=#9dc2e1]${ getAsLocaleString( total.daily.crystal ) }[/color]
${ Lang.deuterium } : [color=#9dc2e1]${ getAsLocaleString( total.daily.deuterium ) }[/color]
${ ( function(){
const planets = { counts: [], used: [] }
const moons = { counts: [], used: [] }
for( const [ key, { fields } ] of Object.entries( player.positions ) ){
const type = key.endsWith( 'P' ) ? planets : moons
type.counts.push( fields.count )
type.used.push( fields.used )
}
let result = `[color=#6f9fc8]${ Lang.planetFields.toUpperCase() }[/color]
Total : ${ getTechnologyResume( planets.counts ) }
${ Lang.used } : ${ getTechnologyResume( planets.used ) }\n`
if( moons.counts.length ){
result += `\n[color=#6f9fc8]${ Lang.moonFields.toUpperCase() }[/color]
Total : ${ getTechnologyResume( moons.counts ) }
${ Lang.used } : ${ getTechnologyResume( moons.used ) }\n`
}
return result
} )() }
${ ( function(){
const results = {}
for( const [ key, { technologies } ] of Object.entries( player.positions ) ){
if( key.endsWith( 'P' ) ){
const { currents, upgraded, upgrades } = technologies
for( const key of GameData.types.planetBuildings ){
const value = upgrades[ key ] ? `[u]${ upgraded[ key ] }[/u]` : currents[ key ]
results[ key ] ||= []
results[ key ].push( value )
}
}
}
let result = `[color=#6f9fc8]${ Lang.planetBuildings.toUpperCase() }[/color]\n`
for( const [ key, value ] of Object.entries( results ) ){
result += `${ Lang.technologies[ key ] } : ${ getTechnologyResume( value ) }\n`
}
return result
} )() } ${ ( function(){
const results = {}
for( const [ key, { technologies } ] of Object.entries( player.positions ) ){
if( key.endsWith( 'M' ) ){
const { currents, upgraded, upgrades } = technologies
for( const key of GameData.types.moonBuildings ){
const value = upgrades[ key ] ? `[u]${ upgraded[ key ] }[/u]` : currents[ key ]
results[ key ] ||= []
results[ key ].push( value )
}
}
}
let result = ''
if( Object.keys( results ).length ){
result = `\n[color=#6f9fc8]${ Lang.moonBuildings.toUpperCase() }[/color]\n`
for( const [ key, value ] of Object.entries( results ) ){
result += `${ Lang.technologies[ key ] } : ${ getTechnologyResume( value ) }\n`
}
}
return result
} )() }
${ ( function(){
const { currents, upgraded, upgrades } = player.researches
let result = `[color=#6f9fc8]${ Lang.researches.toUpperCase() }[/color]\n`
for( const key of Object.keys( currents ) ){
const value = upgrades[ key ] ? `[u]${ upgraded[ key ] }[/u]`: currents[ key ]
result += `${ Lang.technologies[ key ] } : [color=#9dc2e1]${ value }[/color]\n`
}
return result
} )() }
${ ( function(){
const results = {}
for( const [ key, { technologies } ] of Object.entries( player.positions ) ){
const { currents, upgraded, upgrades } = technologies
for( const key of GameData.types.ships ){
const value = upgrades[ key ] ? `[u]${ upgraded[ key ] }[/u]` : currents[ key ]
results[ key ] ||= 0
results[ key ] += value
}
}
let result = `[color=#6f9fc8]${ Lang.fleet.toUpperCase() }[/color]\n`
for( const [ key, value ] of Object.entries( results ) ){
result += `${ Lang.technologies[ key ] } : [color=#9dc2e1]${ getAsLocaleString( value ) }[/color]\n`
}
return result
} )() }
${ ( function(){
const results = {}
for( const [ key, { technologies } ] of Object.entries( player.positions ) ){
if( key.endsWith( 'P' ) ){
const { currents, upgraded, upgrades } = technologies
for( const key of GameData.types.defenses ){
const value = upgrades[ key ] ?`[u]${ upgraded[ key ] }[/u]` : currents[ key ]
results[ key ] ||= []
results[ key ].push( value )
}
}
}
let result = `[color=#6f9fc8]${ Lang.planetDefenses.toUpperCase() }[/color]\n`
for( const [ key, value ] of Object.entries( results ) ){
result += `${ Lang.technologies[ key ] } : ${ getTechnologyResume( value ) }\n`
}
return result
} )() }
${ ( function(){
const results = {}
for( const [ key, { technologies } ] of Object.entries( player.positions ) ){
if( key.endsWith( 'M' ) ){
const { currents, upgraded, upgrades } = technologies
for( const key of GameData.types.defenses ){
const value = upgrades[ key ] ? `[u]${ upgraded[ key ] }[/u]` : currents[ key ]
results[ key ] ||= []
results[ key ].push( value )
}
}
}
let result = ''
if( Object.entries( results ).length ){
result = `[color=#6f9fc8]${ Lang.moonDefenses.toUpperCase() }[/color]\n`
for( const [ key, value ] of Object.entries( results ) ){
result += `${ Lang.technologies[ key ] } : ${ getTechnologyResume( value ) }\n`
}
}
return result
} )() }`
},
getProduction( { player, universe, component } ){
const { counts } = component.points
const { mines, total } = component.productions
const { positions, researches } = player
const [ date, time ] = getDate()
return `[size=14]${ Lang.titles.production( player, universe ) }[/size]
[size=8]${ Lang.titles.generated( date, time ) } [url=https://board.fr.ogame.gameforge.com/index.php?thread/746302-infocompte/]InfoCompte ${ GM_info.script.version }[/url][/size]
${ Lang.classes.player[ player.class ] } & ${ Lang.classes.alliance[ player.alliance.class ] }
[color=#6f9fc8]POSITIONS[/color]
${ ( function(){
let index = 0,
result = ''
for( const [ key, { technologies, temperatures } ] of Object.entries( positions ) ){
if( key.endsWith( 'P' ) ){
const { currents, upgraded, upgrades } = technologies
result += `${ getAsPaddedString( ++index, 2, '0' ) }. `
result += `[color=#9a9ac1]${ upgrades[ 1 ] ? `[u]${ upgraded[ 1 ] }[/u]` : currents[ 1 ] }[/color], `
result += `[color=#8dceec]${ upgrades[ 2 ] ? `[u]${ upgraded[ 2 ] }[/u]` : currents[ 2 ] }[/color], `
result += `[color=#6cc6a3]${ upgrades[ 3 ] ? `[u]${ upgraded[ 3 ] }[/u]` : currents[ 3 ] }[/color], `
result += `[color=#bb875b]${ upgrades[ 217 ]? `[u]${ getAsLocaleString( upgraded[ 217 ] ) }[/u]` : getAsLocaleString( currents[ 217 ] ) }[/color], `
result += `[color=#f5bbb4]${ temperatures.max } °C[/color]\n`
}
}
return result
} )() }
[color=#6f9fc8]${ Lang.researches.toUpperCase() }[/color]
${ Lang.technologies[ 122 ] } : ${ researches.upgrades[ 122 ] ? `[u]${ researches.upgraded[ 122 ] }[/u]` : researches.currents[ 122 ] }
[color=#6f9fc8]${ Lang.noAmProduction.toUpperCase() }[/color]
${ Lang.hourly } : [color=#9a9ac1]${ getAsLocaleString( total.hourly.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( total.hourly.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( total.hourly.deuterium ) }[/color]
${ Lang.daily } : [color=#9a9ac1]${ getAsLocaleString( total.daily.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( total.daily.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( total.daily.deuterium ) }[/color]
${ Lang.weekly } : [color=#9a9ac1]${ getAsLocaleString( total.weekly.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( total.weekly.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( total.weekly.deuterium ) }[/color]
[color=#6f9fc8]${ Lang.minesProduction.toUpperCase() }[/color]
${ Lang.hourly } : [color=#9a9ac1]${ getAsLocaleString( mines.hourly.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( mines.hourly.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( mines.hourly.deuterium ) }[/color]
${ Lang.daily } : [color=#9a9ac1]${ getAsLocaleString( mines.daily.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( mines.daily.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( mines.daily.deuterium ) }[/color]
${ Lang.weekly } : [color=#9a9ac1]${ getAsLocaleString( mines.weekly.metal ) }[/color], [color=#8dceec]${ getAsLocaleString( mines.weekly.crystal ) }[/color], [color=#6cc6a3]${ getAsLocaleString( mines.weekly.deuterium ) }[/color]
[color=#6f9fc8]${ Lang.minesPoints.toUpperCase() }[/color]
${ Lang.metal } : [color=#9a9ac1]${ getAsLocaleString( counts.mineBuildings.metal ) }[/color]
${ Lang.crystal } : [color=#8dceec]${ getAsLocaleString( counts.mineBuildings.crystal ) }[/color]
${ Lang.deuterium } : [color=#6cc6a3]${ getAsLocaleString( counts.mineBuildings.deuterium ) }[/color]
Total : ${ getAsLocaleString( counts.mineBuildings.total ) }`
}
}
} )()
return {
init( data ){
if( !MissingDataComponent.init( data ) ){
switch( currentPage ){
case 'overview':
OverviewComponent.init( data )
break
}
}
}
}
} )()
function getReducedData( storage, page ){
const result = Utils.reduce( storage, page )
if( currentPage !== 'empire' && storage.player?.positions ){
for( const key of Object.keys( storage.player.positions ) ){
if( !page.player.positions[ key ] ){
delete result.player.positions[ key ]
}
}
}
return result
}
const data = getReducedData( StorageData.get(), await PageData.get() )
PageComponent.init( data )
StorageData.set( data )