OGLight script for OGame
// ==UserScript==
// @name OGLight
// @namespace https://openuserjs.org/users/nullNaN
// @version 5.3.2
// @description OGLight script for OGame
// @author Oz
// @license MIT
// @copyright 2019, Oz
// @match https://*.ogame.gameforge.com/game/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant GM_getTab
// @grant GM_saveTab
// @grant GM_notification
// @run-at document-start
// ==/UserScript==
'use strict';
let oglVersion = "5.3.2";
let betaVersion = "-b16";
GM_addStyle(`
html { background-color: #0b1423 !important; }
`);
// redirect user if needed
const oglRedirection = localStorage.getItem('ogl-redirect');
if(oglRedirection?.indexOf('https') > -1)
{
if(typeof window?.GM_addStyle !== typeof undefined)
{
GM_addStyle(`
body { background:#0b1423 !important; }
body * { display:none !important; }
`);
}
localStorage.setItem('ogl-redirect', false);
setTimeout(() => window.location.replace(oglRedirection));
}
// fix for firefox
if(unsafeWindow?.ogl) unsafeWindow.ogl = null;
// update body attributes as fast as possible
const updateOGLBody = () =>
{
document.body.dataset.minipics = localStorage.getItem('ogl_minipics') || false;
document.body.dataset.menulayout = localStorage.getItem('ogl_menulayout') || 0;
document.body.dataset.colorblind = localStorage.getItem('ogl_colorblind') || false;
document.body.dataset.sidepanel = localStorage.getItem('ogl_sidepanelleft') || false;
}
if(document.body)
{
updateOGLBody();
}
else
{
document.addEventListener('readystatechange', () =>
{
if(document.readyState === "loading") updateOGLBody();
else if(!document.body?.dataset?.minipics) updateOGLBody();
});
}
GM_addStyle(`:root{--ogl:#ffb800;--primary:linear-gradient(to bottom,#171d23,#101419);--secondary:linear-gradient(192deg,#252e3a,#171c24 70%);--secondaryReversed:linear-gradient(176deg,#252e3a,#171c24 70%);--tertiary:linear-gradient(to bottom,#293746,#212a36 max(5%,8px),#171c24 max(14%,20px));--date:#9c9cd7;--time:#85c1d3;--texthighlight:#6dbbb3;--metal:#9a9ac1;--crystal:#8dceec;--deut:#41aa9c;--energy:#f5bbb4;--dm:#b58cdb;--food:#c3a2ba;--artefact:#cda126;--population:#ccc;--lifeform:#d569b8;--msu:#c7c7c7;--nothing:#ddd;--resource:#86edfd;--ship:#1dd1a1;--pirate:#ffd60b;--alien:#5ce724;--item:#bf6c4d;--blackhole:#818181;--early:#79a2ff;--late:#df5252;--trader:#ff7d30;--red:#f9392b;--pink:#ff7ba8;--purple:#ba68c8;--indigo:#7e57c2;--blue:#3f51b5;--cyan:#29b6f6;--teal:#06a98b;--green:#4caf50;--lime:#97b327;--yellow:#fbea20;--amber:#ffa000;--orange:#f38b3f;--brown:#5d4037;--grey:#607d8b;--mission1:#ef5f5f;--mission2:#ef5f5f;--mission3:#66cd3d;--mission4:#00c5b2;--mission5:#d97235;--mission6:#e9c74b;--mission7:#5ae8ea;--mission8:#0cc14a;--mission9:#ff4545;--mission10:#97b0c3;--mission15:#527dcb;--mission17:#7eacb5;--mission18:#7eacb5;--inactive:#b3b3b3;--longInactive:#767676;--banned:#ebb3b3;--vacation:#0ff;--honorable:#ff6}body[data-colorblind=true]{--vacation:#8592f5;--honorable:#f9ce27}.material-icons{image-rendering:pixelated;letter-spacing:normal;user-select:none;text-transform:none;white-space:nowrap;word-wrap:normal;-webkit-font-feature-settings:"liga";font-feature-settings:"liga";-webkit-font-smoothing:antialiased;direction:ltr;display:inline-block;transform:rotate(.03deg);font-family:Material Icons!important;font-style:normal!important;font-weight:400!important;font-size:inherit!important;line-height:inherit!important}html,body{background:#030408 url(https://gf2.geo.gfsrv.net/cdn4e/d07c90d96bbc823d6d53953a94aacb.jpg) 50% 0 no-repeat!important}#middle,#right{padding-bottom:70px}body.ogl_destinationPicker #planetList:before{box-shadow:inset 0 0 100px -1px var(--ogl);content:"";opacity:0;pointer-events:none;z-index:10;-webkit-border-radius:7px;border-radius:7px;animation:2.5s ease-in-out infinite pulseOGL;display:block;position:absolute;top:0;bottom:0;left:0;right:0}@keyframes pulseOGL{0%{opacity:0}50%{opacity:.35}to{opacity:0}}body.ogl_destinationPicker .planetlink,body.ogl_destinationPicker .moonlink{cursor:crosshair}line.ogl_line{filter:drop-shadow(0 0 6px #000);marker-end:url(#arrow);marker-start:url(#circle);stroke:#fff;stroke-width:2px}.ui-front:not([aria-describedby=fleetTemplatesEdit]):not(.errorBox):not(:has(#rocketattack)){z-index:9999!important}.ui-widget-overlay{z-index:9998!important}.ogl_unit{white-space:nowrap}.ogl_suffix{margin-left:2px;font-size:smaller;display:inline-block}.ogl_text{color:var(--ogl)!important}.ogl_metal,#resources_metal,.resource.metal,resource-icon.metal .amount{color:var(--metal)!important}.ogl_crystal,#resources_crystal,.resource.crystal,resource-icon.crystal .amount{color:var(--crystal)!important}.ogl_deut,#resources_deuterium,.resource.deuterium,resource-icon.deuterium .amount{color:var(--deut)!important}.ogl_food,#resources_food,.resource.food,resource-icon.food .amount{color:var(--food)!important}.ogl_dm,#resources_darkmatter,.resource.darkmatter{color:var(--dm)!important}.ogl_energy,#resources_energy,.resource.energy,resource-icon.energy .amount{color:var(--energy)!important}.ogl_population,#resources_population,.resource.population,resource-icon.population .amount{color:var(--population)!important}.ogl_artefact{color:var(--artefact)!important}[class*=ogl_lifeform]{color:var(--lifeform)!important}.ogl_msu{color:var(--msu)!important}.ogl_mission1{color:var(--mission1)!important}[data-mission-type="1"]:not(.fleetDetails) .detailsFleet{color:var(--mission1)!important}.ogl_mission2{color:var(--mission2)!important}[data-mission-type="2"]:not(.fleetDetails) .detailsFleet{color:var(--mission2)!important}.ogl_mission3{color:var(--mission3)!important}[data-mission-type="3"]:not(.fleetDetails) .detailsFleet{color:var(--mission3)!important}.ogl_mission4{color:var(--mission4)!important}[data-mission-type="4"]:not(.fleetDetails) .detailsFleet{color:var(--mission4)!important}.ogl_mission5{color:var(--mission5)!important}[data-mission-type="5"]:not(.fleetDetails) .detailsFleet{color:var(--mission5)!important}.ogl_mission6{color:var(--mission6)!important}[data-mission-type="6"]:not(.fleetDetails) .detailsFleet{color:var(--mission6)!important}.ogl_mission7{color:var(--mission7)!important}[data-mission-type="7"]:not(.fleetDetails) .detailsFleet{color:var(--mission7)!important}.ogl_mission8{color:var(--mission8)!important}[data-mission-type="8"]:not(.fleetDetails) .detailsFleet{color:var(--mission8)!important}.ogl_mission9{color:var(--mission9)!important}[data-mission-type="9"]:not(.fleetDetails) .detailsFleet{color:var(--mission9)!important}.ogl_mission10{color:var(--mission10)!important}[data-mission-type="10"]:not(.fleetDetails) .detailsFleet{color:var(--mission10)!important}.ogl_mission11{color:var(--mission11)!important}[data-mission-type="11"]:not(.fleetDetails) .detailsFleet{color:var(--mission11)!important}.ogl_mission12{color:var(--mission12)!important}[data-mission-type="12"]:not(.fleetDetails) .detailsFleet{color:var(--mission12)!important}.ogl_mission13{color:var(--mission13)!important}[data-mission-type="13"]:not(.fleetDetails) .detailsFleet{color:var(--mission13)!important}.ogl_mission14{color:var(--mission14)!important}[data-mission-type="14"]:not(.fleetDetails) .detailsFleet{color:var(--mission14)!important}.ogl_mission15{color:var(--mission15)!important}[data-mission-type="15"]:not(.fleetDetails) .detailsFleet{color:var(--mission15)!important}.ogl_mission17{color:var(--mission17)!important}[data-mission-type="17"]:not(.fleetDetails) .detailsFleet{color:var(--mission17)!important}.ogl_mission18{color:var(--mission18)!important}[data-mission-type="18"]:not(.fleetDetails) .detailsFleet{color:var(--mission18)!important}[data-mission-type]{background:#121b22!important}[data-mission-type] .detailsFleet span{filter:brightness(1.5)saturate(.8)}[data-mission-type="1"]{background:linear-gradient(90deg,#121b22,#482018,#121b22)!important}[data-mission-type="2"]{background:linear-gradient(90deg,#121b22,#54271f,#121b22)!important}[data-mission-type="3"]{background:linear-gradient(90deg,#121b22,#2a5d21,#121b22)!important}[data-mission-type="4"]{background:linear-gradient(90deg,#121b22,#104841,#121b22)!important}[data-mission-type="5"]{background:linear-gradient(90deg,#121b22,#643d25,#121b22)!important}[data-mission-type="6"]{background:linear-gradient(90deg,#121b22,#4c401f,#121b22)!important}[data-mission-type="7"]{background:linear-gradient(90deg,#121b22,#214350,#121b22)!important}[data-mission-type="8"]{background:linear-gradient(90deg,#121b22,#004011,#121b22)!important}[data-mission-type="9"]{background:linear-gradient(90deg,#121b22,#4a1b14,#121b22)!important}[data-mission-type="10"]{background:linear-gradient(90deg,#121b22,#3f4b54,#121b22)!important}[data-mission-type="15"]{background:linear-gradient(90deg,#121b22,#182542,#121b22)!important}[data-mission-type="17"]{background:linear-gradient(90deg,#121b22,#203642,#121b22)!important}[data-mission-type="18"]{background:linear-gradient(90deg,#121b22,#203642,#121b22)!important}.ogl_icon,.ogl_metal.ogl_icon,.ogl_crystal.ogl_icon,.ogl_deut.ogl_icon,.ogl_food.ogl_icon,.ogl_dm.ogl_icon,.ogl_energy.ogl_icon,.ogl_artefact.ogl_icon,.ogl_population.ogl_icon,.ogl_icon.ogl_msu{white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;align-items:center;padding:3px;display:flex;position:relative}.ogl_icon[class*=ogl_1] .ogl_icon[class*=ogl_2]{white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;align-items:center;padding:3px;display:flex;position:relative}.ogl_icon[class*=ogl_mission]{white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;align-items:center;padding:3px;display:flex;position:relative}.ogl_icon[class*=ogl_lifeform]{white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;align-items:center;padding:3px;display:flex;position:relative}.ogl_metal.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_crystal.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_deut.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_food.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_dm.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_energy.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_artefact.ogl_icon:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_icon.ogl_population:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_icon.ogl_msu:before{content:"";height:18px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf3.geo.gfsrv.net/cdned/7f14c18b15064d2604c5476f5d10b3.png);background-size:302px;-webkit-border-radius:3px;border-radius:3px;width:28px;margin-right:10px;display:inline-block}.ogl_icon.ogl_metal:before{background-position:1% 11%}.ogl_icon.ogl_crystal:before{background-position:16% 11%}.ogl_icon.ogl_deut:before{background-position:30% 11%}.ogl_icon.ogl_dm:before{background-position:57% 11%}.ogl_icon.ogl_energy:before{background-position:43% 11%}.ogl_icon.ogl_food:before{background-position:85% 11%}.ogl_icon.ogl_population:before{background-position:98% 11%}.ogl_icon.ogl_artefact:before{background-image:url(https://image.board.gameforge.com/uploads/ogame/fr/announcement_ogame_fr_59cb6f773531d4ad73e508c140cd2d3c.png);background-size:28px}.ogl_icon.ogl_plus:after{color:#fff;content:"+";background:linear-gradient(164deg,#434343,#838383);-webkit-border-radius:3px;border-radius:3px;justify-content:center;align-items:center;width:12px;height:12px;font-size:10px;font-weight:700;display:flex;position:absolute;top:3px;left:15px;box-shadow:-1px 2px 3px #000}:is(.ogl_miniStats,.ogl_recap,.ogl_stats,.ogl_todoList) .ogl_icon.ogl_metal:before{image-rendering:auto;background-image:url(https://gf2.geo.gfsrv.net/cdn1c/4230ff01e100a38a72dadfa7de0661.png);background-size:28px}:is(.ogl_miniStats,.ogl_recap,.ogl_stats,.ogl_todoList) .ogl_icon.ogl_crystal:before{image-rendering:auto;background-image:url(https://gf1.geo.gfsrv.net/cdn65/596ba85baa74145390e04f7428d93e.png);background-size:28px}:is(.ogl_miniStats,.ogl_recap,.ogl_stats,.ogl_todoList) .ogl_icon.ogl_deut:before{image-rendering:auto;background-image:url(https://gf1.geo.gfsrv.net/cdnc0/7a7bf2b8edcd74ebafe31dfbae14aa.png);background-size:28px}:is(.ogl_miniStats,.ogl_recap,.ogl_stats,.ogl_todoList) .ogl_icon.ogl_dm:before{filter:hue-rotate(40deg)saturate();image-rendering:auto;background-image:url(https://gf2.geo.gfsrv.net/cdna3/4de426cb95e11af9cdabb901dfe802.png);background-size:28px}:is(.ogl_miniStats,.ogl_recap,.ogl_stats,.ogl_todoList) .ogl_icon.ogl_artefact:before{filter:hue-rotate(200deg)saturate(4);image-rendering:auto;background-image:url(https://gf1.geo.gfsrv.net/cdn65/596ba85baa74145390e04f7428d93e.png);background-size:28px;transform:scaleX(-1)}.ogl_icon[class*=ogl_1]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_2]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_3]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_4]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_5]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_6]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_7]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_8]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon[class*=ogl_9]:before{content:"";image-rendering:auto;vertical-align:text-bottom;background-position:50%;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:5px;display:inline-block}.ogl_icon.ogl_200:before{content:"close";text-align:center;background:linear-gradient(45deg,#784242,#dd4242);font-family:Material Icons;line-height:18px}.ogl_icon.ogl_1:before{background-image:url(https://gf2.geo.gfsrv.net/cdn74/696be2632de1977d0bd923e05d37b0.jpg)}.ogl_icon.ogl_2:before{background-image:url(https://gf3.geo.gfsrv.net/cdn21/6468ceef42917eea7b76f72dd3b70a.jpg)}.ogl_icon.ogl_3:before{background-image:url(https://gf1.geo.gfsrv.net/cdn97/f208f485246b04abc54cb9a229fff7.jpg)}.ogl_icon.ogl_4:before{background-image:url(https://gf2.geo.gfsrv.net/cdn70/6ae8432102c9b802ec4eec6917e020.jpg)}.ogl_icon.ogl_12:before{background-image:url(https://gf2.geo.gfsrv.net/cdn79/42f8c414d245b04a0104f411958dde.jpg)}.ogl_icon.ogl_14:before{background-image:url(https://gf3.geo.gfsrv.net/cdn21/034ea2b2e9d16eb350116cb1391a8f.jpg)}.ogl_icon.ogl_15:before{background-image:url(https://gf1.geo.gfsrv.net/cdn93/203bf2febc6a24812457f1611621c5.jpg)}.ogl_icon.ogl_21:before{background-image:url(https://gf3.geo.gfsrv.net/cdn83/8443bf78a6cbe448f68c791f3532f6.jpg)}.ogl_icon.ogl_22:before{background-image:url(https://gf3.geo.gfsrv.net/cdn8c/472a30155cdad9776b319a6590099c.jpg)}.ogl_icon.ogl_23:before{background-image:url(https://gf3.geo.gfsrv.net/cdnb3/c95c16f22b5a2c6ced74bcf32f3932.jpg)}.ogl_icon.ogl_24:before{background-image:url(https://gf2.geo.gfsrv.net/cdn70/6fb935649c27645d709977ad47cb98.jpg)}.ogl_icon.ogl_31:before{background-image:url(https://gf3.geo.gfsrv.net/cdn24/81c2103d9ae1d22abb23dddd4e45cc.jpg)}.ogl_icon.ogl_33:before{background-image:url(https://gf3.geo.gfsrv.net/cdn8c/162541a8e2df809b2d8655334157b1.jpg)}.ogl_icon.ogl_34:before{background-image:url(https://gf3.geo.gfsrv.net/cdn88/8cdbff7898af1160195944b20feed7.jpg)}.ogl_icon.ogl_36:before{background-image:url(https://gf2.geo.gfsrv.net/cdn14/3ab386e1e6bedbcf263197fe268bf2.jpg)}.ogl_icon.ogl_41:before{background-image:url(https://gf1.geo.gfsrv.net/cdn65/94b9b8a961d01b3dff6cc8d1962031.jpg)}.ogl_icon.ogl_42:before{background-image:url(https://gf1.geo.gfsrv.net/cdn03/47840e9f771909ba356a6384799005.jpg)}.ogl_icon.ogl_43:before{background-image:url(https://gf2.geo.gfsrv.net/cdnda/f5b003cb40143133188be46600b0a7.jpg)}.ogl_icon.ogl_44:before{background-image:url(https://gf2.geo.gfsrv.net/cdnd7/99d1eeb073c2654140cd353677881e.jpg)}.ogl_icon.ogl_109:before{background-image:url(https://gf2.geo.gfsrv.net/cdna7/d6e7869f6b8150c44e275e38c0b27c.jpg)}.ogl_icon.ogl_110:before{background-image:url(https://gf1.geo.gfsrv.net/cdn9d/96f4ec3ea10b15523591efb7d1c5f7.jpg)}.ogl_icon.ogl_111:before{background-image:url(https://gf3.geo.gfsrv.net/cdnb3/8bcbf1b317ff5c97b969b69e6ffb11.jpg)}.ogl_icon.ogl_115:before{background-image:url(https://gf2.geo.gfsrv.net/cdnd5/5c1c1ea00023c4552489d9d13c8944.jpg)}.ogl_icon.ogl_117:before{background-image:url(https://gf1.geo.gfsrv.net/cdn62/f5755473fdb7dc5fafa863a6f3507a.jpg)}.ogl_icon.ogl_118:before{background-image:url(https://gf2.geo.gfsrv.net/cdn78/6bba453cc20b677b268a1160f23cc1.jpg)}.ogl_icon.ogl_113:before{background-image:url(https://gf2.geo.gfsrv.net/cdn77/6f71772b30c8f00b94a6888cd6846b.jpg)}.ogl_icon.ogl_122:before{background-image:url(https://gf1.geo.gfsrv.net/cdncf/34a78ce2f7f4ad15de745ade2a96ec.jpg)}.ogl_icon.ogl_124:before{background-image:url(https://gf3.geo.gfsrv.net/cdnb1/148d695e299644aacdd2ef9149db0d.jpg)}.ogl_icon.ogl_202:before{background-image:url(https://gf2.geo.gfsrv.net/cdnd9/60555c3c87b9eb3b5ddf76780b5712.jpg)}.ogl_icon.ogl_203:before{background-image:url(https://gf1.geo.gfsrv.net/cdn34/fdbcc505474e3e108d10a3ed4a19f4.jpg)}.ogl_icon.ogl_204:before{background-image:url(https://gf2.geo.gfsrv.net/cdnd2/9ed5c1b6aea28fa51f84cdb8cb1e7e.jpg)}.ogl_icon.ogl_205:before{background-image:url(https://gf1.geo.gfsrv.net/cdnf1/8266a2cbae5ad630c5fedbdf270f3e.jpg)}.ogl_icon.ogl_206:before{background-image:url(https://gf2.geo.gfsrv.net/cdn45/b7ee4f9d556a0f39dae8d2133e05b7.jpg)}.ogl_icon.ogl_207:before{background-image:url(https://gf1.geo.gfsrv.net/cdn32/3f4a081f4d15662bed33473db53d5b.jpg)}.ogl_icon.ogl_208:before{background-image:url(https://gf1.geo.gfsrv.net/cdn6f/41a21e4253d2231f8937ddef1ba43e.jpg)}.ogl_icon.ogl_209:before{background-image:url(https://gf1.geo.gfsrv.net/cdn07/6246eb3d7fa67414f6b818fa79dd9b.jpg)}.ogl_icon.ogl_210:before{background-image:url(https://gf3.geo.gfsrv.net/cdnb5/347821e80cafc52aec04f27c3a2a4d.jpg)}.ogl_icon.ogl_211:before{background-image:url(https://gf1.geo.gfsrv.net/cdnca/4d55a520aed09d0c43e7b962f33e27.jpg)}.ogl_icon.ogl_213:before{background-image:url(https://gf3.geo.gfsrv.net/cdn2a/c2b9fedc9c93ef22f2739c49fbac52.jpg)}.ogl_icon.ogl_214:before{background-image:url(https://gf3.geo.gfsrv.net/cdn84/155e9e24fc1d34ed4660de8d428f45.jpg)}.ogl_icon.ogl_215:before{background-image:url(https://gf3.geo.gfsrv.net/cdn5a/24f511ec14a71e2d83fd750aa0dee2.jpg)}.ogl_icon.ogl_217:before{background-image:url(https://gf3.geo.gfsrv.net/cdn26/28e8d79a5b489dc795cc47f3adf165.jpg)}.ogl_icon.ogl_218:before{background-image:url(https://gf1.geo.gfsrv.net/cdn39/12d016c8bb0d71e053b901560c17cc.jpg)}.ogl_icon.ogl_219:before{background-image:url(https://gf3.geo.gfsrv.net/cdne2/b8d8d18f2baf674acedb7504c7cc83.jpg)}.ogl_icon.ogl_401:before{background-image:url(https://gf2.geo.gfsrv.net/cdnaf/b5d139528cdf1233e61bd58184e1c5.jpg)}.ogl_icon.ogl_402:before{background-image:url(https://gf2.geo.gfsrv.net/cdn7d/34b3f95bf2d4e3355fed09a3e1877e.jpg)}.ogl_icon.ogl_403:before{background-image:url(https://gf2.geo.gfsrv.net/cdnd4/9d88c2d9b8e5872bef32a7f8659695.jpg)}.ogl_icon.ogl_404:before{background-image:url(https://gf3.geo.gfsrv.net/cdn2c/0fc6c29d06858b5b9ca0b0a4d1532e.jpg)}.ogl_icon.ogl_405:before{background-image:url(https://gf2.geo.gfsrv.net/cdn11/4dd51eeb4ab03af617828169bffd5b.jpg)}.ogl_icon.ogl_406:before{background-image:url(https://gf1.geo.gfsrv.net/cdn07/ea3e0adf01fb3cf64e1938a7c55dfb.jpg)}.ogl_icon.ogl_407:before{background-image:url(https://gf2.geo.gfsrv.net/cdna9/4d20894a828929ff5a61f62c757149.jpg)}.ogl_icon.ogl_408:before{background-image:url(https://gf2.geo.gfsrv.net/cdnda/533c32ff26f4db6857e3e41c09d443.jpg)}.ogl_icon.ogl_502:before{background-image:url(https://gf2.geo.gfsrv.net/cdn7a/40a392214240328e42014108815526.jpg)}.ogl_icon[class*=ogl_mission]:before{content:"";vertical-align:middle;background-image:url(https://gf2.geo.gfsrv.net/cdn14/f45a18b5e55d2d38e7bdc3151b1fee.jpg);background-position:0 0;-webkit-border-radius:3px;border-radius:3px;width:28px;height:18px;margin-right:10px;display:inline-block;background-size:344px!important}.ogl_icon.ogl_mission1:before{background-position:80.05% 0!important}.ogl_icon.ogl_mission2:before{background-position:99.7% 0!important}.ogl_icon.ogl_mission3:before{background-position:50% 0!important}.ogl_icon.ogl_mission4:before{background-position:30% 0!important}.ogl_icon.ogl_mission5:before{background-position:69.5% 0!important}.ogl_icon.ogl_mission6:before{background-position:59.75% 0!important}.ogl_icon.ogl_mission7:before{background-position:20.75% 0!important}.ogl_icon.ogl_mission8:before{background-position:40.1% 0!important}.ogl_icon.ogl_mission9:before{background-position:89% 0!important}.ogl_icon.ogl_mission15:before{background-position:.2% 0!important}.ogl_icon.ogl_mission18:before{background:url(https://gf2.geo.gfsrv.net/cdna8/1fc8d15445e97c10c7b6881bccabb2.gif);background-size:18px!important}.ogl_lifeform0.ogl_icon:before{content:"-"}.ogl_lifeform1.ogl_icon:before{content:"";height:24px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf2.geo.gfsrv.net/cdna5/5681003b4f1fcb30edc5d0e62382a2.png);background-size:245px;width:24px;display:inline-block}.ogl_lifeform2.ogl_icon:before{content:"";height:24px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf2.geo.gfsrv.net/cdna5/5681003b4f1fcb30edc5d0e62382a2.png);background-size:245px;width:24px;display:inline-block}.ogl_lifeform3.ogl_icon:before{content:"";height:24px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf2.geo.gfsrv.net/cdna5/5681003b4f1fcb30edc5d0e62382a2.png);background-size:245px;width:24px;display:inline-block}.ogl_lifeform4.ogl_icon:before{content:"";height:24px;image-rendering:pixelated;vertical-align:middle;background-image:url(https://gf2.geo.gfsrv.net/cdna5/5681003b4f1fcb30edc5d0e62382a2.png);background-size:245px;width:24px;display:inline-block}.ogl_icon.ogl_lifeform0:before{background-position:1% 11%}.ogl_icon.ogl_lifeform1:before{background-position:0 86%}.ogl_icon.ogl_lifeform2:before{background-position:11% 86%}.ogl_icon.ogl_lifeform3:before{background-position:22% 86%}.ogl_icon.ogl_lifeform4:before{background-position:33% 86%}.ogl_icon.ogl_msu:before{color:#fff;content:"MSU";background:0 0;justify-content:center;align-items:center;font-size:11px;display:flex}.ogl_gridIcon .ogl_icon{grid-gap:7px;text-align:center;justify-content:center;padding-top:6px;display:grid}.ogl_gridIcon .ogl_icon:before{margin:auto}.ogl_header{color:#6f9fc8;text-align:center;height:27px;font-size:11px;font-weight:700;line-height:27px;position:relative}.ogl_header .material-icons{font-size:17px!important;line-height:28px!important}.ogl_button,a.ogl_button{cursor:pointer;text-align:center;text-shadow:1px 1px #000;user-select:none;background:linear-gradient(#405064,#2d3743 2px,#181e25);border:1px solid #17191c;-webkit-border-radius:3px;border-radius:3px;padding:0 4px;text-decoration:none;display:inline-block;color:#b7c1c9!important;line-height:26px!important}.ogl_button:hover{color:var(--ogl)!important}.ogl_invisible{visibility:hidden}.ogl_hidden{display:none!important}.ogl_reversed{transform:scaleX(-1)}.ogl_blocCenter{margin:auto}.ogl_textCenter{text-align:center;justify-content:center}.ogl_textRight{text-align:right;justify-content:end}.ogl_disabled{color:rgba(255,255,255,.2);opacity:.5;pointer-events:none;user-select:none}.ogl_interactive{cursor:pointer}.ogl_noTouch{pointer-events:none!important}.ogl_slidingText{grid-gap:20px;white-space:nowrap;width:100%;position:relative;overflow:hidden;display:inline-flex!important}.ogl_slidingText:before{content:attr(data-text);animation:6s linear infinite textSlideLeft}.ogl_slidingText:after{content:attr(data-text);animation:6s linear infinite textSlideLeft}@keyframes textSlideLeft{0%{transform:translate(20px)}to{transform:translate(-100%)}}[data-status=pending]{pointer-events:none;color:orange!important}[data-status=done]{color:green!important}time{color:var(--time)}time span{color:var(--date)}.menubutton.ogl_active .textlabel{color:#75ffcc!important}#productionboxBottom time{text-align:center;margin-top:10px;font-size:11px}[data-output-time]{user-select:none;white-space:nowrap;grid-template-columns:auto 6px auto;position:relative;overflow:hidden;color:transparent!important;display:inline-grid!important}[data-output-date]{user-select:none;white-space:nowrap;grid-template-columns:auto 6px auto;position:relative;overflow:hidden;color:transparent!important;display:inline-grid!important}[data-output-time]:not([data-output-date]){grid-template-columns:0 auto}[data-output-time] span{display:none}[data-output-date] span{display:none}[data-output-date]:before{color:var(--date);content:attr(data-output-date)}[data-output-time]:after{color:var(--time);content:attr(data-output-time)}[data-output-time=Invalid\ Date]{display:none!important}.honorRank.rank_0,.honorRank.rank_undefined{display:none}[data-galaxy]{color:#c3c3c3;cursor:pointer}[data-galaxy]:hover{color:#fff;text-decoration:underline}[data-galaxy].ogl_active{color:#c3c3c3;box-shadow:inset 0 0 0 2px rgba(255,165,0,.2)}.galaxyCell.cellPlayerName.ogl_active{box-shadow:inset 0 0 0 2px rgba(255,165,0,.2)}.ogl_tooltip{box-sizing:border-box;opacity:0;pointer-events:none;z-index:1000002;-webkit-border-radius:4px;border-radius:4px;padding:10px;font-size:11px;position:absolute;top:0;left:0}.ogl_tooltip:not(:has(.ogl_close)){pointer-events:none!important}.ogl_tooltip:before{-webkit-border-radius:inherit;border-radius:inherit;content:"";position:absolute;top:10px;bottom:10px;left:10px;right:10px;box-shadow:0 0 15px 5px rgba(0,0,0,.6),0 0 4px 1px rgba(0,0,0,.7)}.ogl_tooltip .ogl_tooltipTriangle{pointer-events:none;background:#171c24;width:15px;height:15px;position:absolute;box-shadow:0 0 15px 5px rgba(0,0,0,.6),0 0 4px 1px rgba(0,0,0,.7)}.ogl_tooltip[data-direction=top] .ogl_tooltipTriangle{transform:translate(50%,-50%)rotate(45deg)}.ogl_tooltip[data-direction=bottom] .ogl_tooltipTriangle{background:#293746;transform:translate(50%,50%)rotate(45deg)}.ogl_tooltip[data-direction=left] .ogl_tooltipTriangle{transform:translate(-50%,50%)rotate(45deg)}.ogl_tooltip[data-direction=right] .ogl_tooltipTriangle{transform:translate(50%,50%)rotate(45deg)}.ogl_tooltip .ogl_close{color:#fff;cursor:pointer;z-index:1000004;background:#7c3434;-webkit-border-radius:4px;border-radius:4px;justify-content:center;align-items:center;width:22px;height:22px;position:absolute;top:0;right:0;box-shadow:0 0 8px rgba(0,0,0,.6);font-size:16px!important;display:flex!important}.ogl_tooltip .ogl_close:hover{background:#9f3d3d}.ogl_tooltip.ogl_active{animation-fill-mode:forwards!important}.ogl_tooltip[data-direction=top].ogl_active{animation:.1s appearTop}@keyframes appearTop{0%{opacity:0;margin-top:20px}to{opacity:1;margin-top:0}99%{pointer-events:none}to{pointer-events:all}}.ogl_tooltip[data-direction=bottom].ogl_active{animation:.1s appearBottom}@keyframes appearBottom{0%{opacity:0;margin-top:-20px}to{opacity:1;margin-top:0}99%{pointer-events:none}to{pointer-events:all}}.ogl_tooltip[data-direction=left].ogl_active{animation:.1s appearLeft}@keyframes appearLeft{0%{opacity:0;margin-left:20px}to{opacity:1;margin-left:0}99%{pointer-events:none}to{pointer-events:all}}.ogl_tooltip[data-direction=right].ogl_active{animation:.1s appearRight}@keyframes appearRight{0%{opacity:0;margin-left:-20px}to{opacity:1;margin-left:0}99%{pointer-events:none}to{pointer-events:all}}.ogl_tooltip hr,.ogl_notification hr{background:#1e252e;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_tooltip>div:not(.ogl_tooltipTriangle):not(.ogl_close){background:var(--tertiary);-webkit-border-radius:inherit;border-radius:inherit;z-index:1000003;max-width:400px;max-height:90vh;padding:16px 20px;line-height:1.25;position:relative;overflow-x:hidden;overflow-y:auto;display:block!important}.ogl_tooltip .ogl_colorpicker{grid-gap:3px;grid-template-rows:repeat(5,1fr);grid-auto-flow:column;display:grid!important}[class*=tooltip]{user-select:none!important}[class*=tooltip] input{box-sizing:border-box;max-width:100%}.ogl_colorpicker>div{box-sizing:border-box;cursor:pointer;-webkit-border-radius:50%;border-radius:50%;width:24px;height:24px}.ogl_planetIcon,.ogl_moonIcon,.ogl_flagIcon,.ogl_searchIcon,.ogl_pinIcon,.ogl_fleetIcon{text-align:center!important;vertical-align:text-top!important;font-style:normal!important;display:inline-block!important}.ogl_planetIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_moonIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_flagIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_searchIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_pinIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_fleetIcon:before{font-family:Material Icons;font-size:20px!important}.ogl_planetIcon:before{content:"language"}.ogl_moonIcon:before{content:"bedtime"}.ogl_flagIcon:before{content:"flag"}.ogl_pinIcon:before{content:"keep"}.ogl_searchIcon:before{content:"search"}.ogl_fleetIcon:before{content:"send"}#bar{grid-gap:20px!important;line-height:17px!important}#bar li{list-style:none!important}#fleet1 .content{padding-top:16px!important;padding-bottom:30px!important}#fleet1 .ogl_shipFlag{box-sizing:border-box;grid-gap:4px;text-align:center;background:linear-gradient(#0d1014 30%,transparent);justify-content:space-evenly;width:100%;padding:0 10px;display:flex;position:absolute;top:0;right:0}#fleet1 .ogl_shipFlag>*{color:#b1c2cb;text-shadow:1px 2px #000;width:20px;display:block;position:relative;top:-4px;font-size:16px!important;line-height:14px!important}#fleet1 .ogl_shipFlag>:hover{color:#fff}#fleet1 .ogl_fav:not(.ogl_grayed){color:var(--yellow)}#fleet1 .ogl_shipLock:not(.ogl_grayed){color:var(--red)}#fleet1 .ogl_shipLock,#fleet1 .ogl_reverse{font-size:14px!important}#fleet1 progress{appearance:none;z-index:10;background:var(--capacity);border:0;width:655px;height:5px;display:block;position:absolute;bottom:-5px;left:5px}#fleet1 .capacityProgress{position:relative}#fleet1 .capacityProgress:before{content:attr(data-rawCargo);text-align:center;background:#0c1014;-webkit-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;width:658px;padding:6px 0;font-size:11px;display:inline-block;position:absolute;top:5px;left:3px}#fleet1 .capacityProgress:after{content:attr(data-percentResources)"%";left:var(--currentCapacityPercent);text-shadow:2px 2px 1px #000;font-size:10px;transition:left .5s;display:block;position:absolute;top:-14px;transform:translate(5px)}#fleet1 progress::-webkit-progress-value{backdrop-filter:brightness(1.8);background:rgba(255,255,255,.1);transition:width .5s;box-shadow:5px 0 10px #000}#fleet1 progress::-moz-progress-bar{backdrop-filter:brightness(1.8);background:rgba(255,255,255,.1);transition:width .5s;box-shadow:5px 0 10px #000}.ogl_requiredShips{user-select:none;justify-content:center;align-items:center;width:80px;display:grid}#warning .ogl_requiredShips{grid-gap:28px;width:100%;display:flex}.ogl_requiredShips .ogl_notEnough{color:var(--red);filter:none}.ogl_required{white-space:nowrap;background:linear-gradient(145deg,#000,transparent);-webkit-border-radius:3px;border-radius:3px;font-size:10px;overflow:hidden;padding:0!important}.ogl_required:before{vertical-align:middle!important}.ogl_required:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_maxShip{box-sizing:border-box;color:var(--red);cursor:pointer;text-align:right;user-select:none;background:#3c1a1a;-webkit-border-radius:0;border-radius:0;height:14px;padding:0 5px;font-size:10px;line-height:14px;position:absolute;bottom:19px;left:2px;right:2px}.ogl_maxShip:hover{box-shadow:0 0 0 2px var(--ogl)}.resourceIcon .ogl_maxShip{bottom:0}.ogl_limiterLabel{background:var(--secondary);cursor:pointer;grid-gap:5px;user-select:none;-webkit-border-radius:3px;border-radius:3px;align-items:center;height:28px;padding:0 9px;display:inline-flex}.ogl_limiterGroup{background:var(--secondary);user-select:none;-webkit-border-radius:3px;border-radius:3px;align-items:center;height:28px;margin-left:auto;padding:0 9px;display:inline-flex}.ogl_limiterGroup>i{margin:0 5px}.ogl_limiterGroup .ogl_icon:first-child{margin-left:5px}.ogl_limiterGroup .ogl_icon:before{margin-right:0}.ogl_limiterGroup .ogl_icon:hover{cursor:pointer}.ogl_limiterGroup .ogl_icon:hover:before{box-shadow:0 0 0 2px var(--ogl)}.ogl_limiterGroup .ogl_icon.ogl_active:before{box-shadow:0 0 0 2px #fff}.ogl_limiterGroup:has(.ogl_active:not(.ogl_200)){box-shadow:0 0 0 2px var(--red)}#fleet2 #fleetBriefingPart1 li{margin-bottom:1px!important}#fleet2[data-selected-mission="4"] .ogl_return{opacity:.6}#fleet2 #buttonz .header,#fleet2 #buttonz .footer,#fleet2 .c-left,#fleet2 .c-right{display:none!important}#fleet2 #buttonz .content{margin:0!important;padding:2px 0!important}#fleet2 #resources.lifeforms-enabled{height:216px!important}#fleet2 #buttonz div.move-box{top:-1px!important;right:7px!important}#fleet2 #buttonz ul#missions{height:auto!important}#fleet2 #buttonz ul li span{min-width:122px!important;height:12px!important}#fleet2 #mission{margin:auto!important}#fleet2 div#mission .percentageBarWrapper{margin-top:10px}#fleet1 .ajax_loading_indicator,#fleet2 .ajax_loading_indicator{transform:scale(.5)}#speedPercentage{float:none!important;margin:auto!important}.percentageBar .steps .step:not(.selected){line-height:20px!important}#speedPercentage .bar{pointer-events:none}.technology.ogl_active .icon{border:2px solid #36d7e7!important}.technology.ogl_active .icon:before{content:"";pointer-events:none;z-index:0;background-color:rgba(54,215,231,.25);position:absolute;top:0;bottom:0;left:0;right:0}.technology input[type=number]{box-shadow:none!important;background:#98b2bf!important;border:none!important;-webkit-border-radius:2px!important;border-radius:2px!important;height:20px!important;bottom:-20px!important}.technology input[type=text]{box-shadow:none!important;background:#98b2bf!important;border:none!important;-webkit-border-radius:2px!important;border-radius:2px!important;height:20px!important;bottom:-20px!important}.ogl_notEnough{filter:sepia()hue-rotate(300deg)}.technology.ogl_notEnough{filter:none}.technology.ogl_notEnough .icon{filter:grayscale()brightness(.5)}.technology.ogl_notEnough input{cursor:not-allowed!important;background:#525556!important}.technology input.ogl_flashNotEnough{background:#cf7e7e!important}.technology:hover{z-index:2}.technology .icon{position:relative;-webkit-border-radius:0!important;border-radius:0!important;box-shadow:0 0 0 1px #000!important}.technology .icon>*{z-index:1;position:relative}.technology[data-status=active] .icon{box-shadow:0 0 5px 2px var(--ogl)}.technology.showsDetails .icon{border:2px solid var(--ogl)!important}.technology .icon:hover{border:2px solid var(--ogl)!important}.technology .icon .upgrade{-webkit-border-radius:0!important;border-radius:0!important;box-shadow:0 0 6px rgba(0,0,0,.8)!important}.technology .icon .upgrade:after{border-color:transparent transparent currentColor!important}.technology .icon .level,.technology .icon .amount{background:var(--primary)!important;-webkit-border-radius:0!important;border-radius:0!important}#technologydetails h3,#technologydetails .level,#technologydetails .amount{color:var(--ogl)!important}#fleetdispatchcomponent #allornone{width:654px!important;padding:0!important;left:5px!important}#fleetdispatchcomponent .allornonewrap{box-sizing:border-box;align-items:center;display:flex;background:0 0!important;border:none!important;width:100%!important;padding:24px 9px 15px!important}#fleetdispatchcomponent .allornonewrap>div:not(.clearfloat){margin-right:4px!important}#fleet1 .allornonewrap .firstcol{display:grid;grid-gap:5px!important;justify-content:space-between!important;width:auto!important}#fleetdispatchcomponent #continueToFleet2{margin-left:auto}#fleetdispatchcomponent #allornone .info{display:none}#fleetdispatchcomponent #buttonz #battleships{width:408px!important}#fleetdispatchcomponent #buttonz #civilships{width:254px!important}#fleetdispatchcomponent #buttonz #battleships ul,#fleetdispatchcomponent #buttonz #civilships ul{padding:0!important}#fleetdispatchcomponent #buttonz #battleships ul{margin-left:8px!important}#fleetdispatchcomponent #buttonz #battleships .header,#fleetdispatchcomponent #buttonz #civilships .header{display:none!important}#fleetdispatchcomponent #buttonz #battleships .header{border-right:1px solid #000;-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}#fleetdispatchcomponent #buttonz #civilships .header{border-left:1px solid #000;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}#fleetdispatchcomponent .resourceIcon{cursor:default;position:relative}#fleetdispatchcomponent .ogl_keepRecap{box-sizing:border-box;color:#f45757;text-align:right;background:#4c1b1b;width:100%;padding-right:5px;font-size:10px;position:absolute;bottom:0}#fleetdispatchcomponent fieldset,#jumpgate fieldset{box-sizing:border-box;color:#fff;grid-gap:10px;background:#0c1014;-webkit-border-radius:3px;border-radius:3px;width:656px;margin:10px 5px 5px;padding:12px;display:flex}#jumpgate fieldset{width:625px}#fleetdispatchcomponent fieldset legend,#jumpgate fieldset legend{color:#6f9fc8}#fleetdispatchcomponent .resourceIcon{box-shadow:inset -8px 7px 10px rgba(0,0,0,.5)}#allornone .secondcol{grid-gap:4px;align-items:center;background:0 0!important;border:none!important;width:auto!important;padding:5px!important;display:inline-flex!important}#allornone .secondcol .clearfloat{display:none!important}#allornone .secondcol .ogl_icon:not(.ogl_icon .ogl_icon):before{width:31px;height:31px;box-shadow:inset 0 0 1px 1px #000}#allornone .secondcol .ogl_icon:before{margin:0}#allornone .secondcol .ogl_icon .ogl_icon:before{-webkit-border-radius:10px 10px 10px 0;border-radius:10px 10px 10px 0;width:18px;box-shadow:0 0 0 2px #345eb4,0 0 2px 4px rgba(0,0,0,.7)}#allornone .secondcol .ogl_icon{cursor:pointer;padding:0;position:relative}#allornone .secondcol .ogl_icon .ogl_icon{position:absolute;top:-5px;right:-4px;transform:scale(.8)}#resetall,#sendall{-webkit-border-radius:3px;border-radius:3px;overflow:hidden;transform:scale(.97)}#galaxyLoading:after{content:attr(data-currentposition);background:rgba(0,0,0,.7);-webkit-border-radius:8px;border-radius:8px;padding:5px;font-size:13px;font-weight:700;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}#headerbarcomponent{width:1063px!important}#commandercomponent{transform:translate(66px)}#bar .OGameClock{grid-gap:0!important;width:auto!important;margin:0!important}#bar #headerBarLinks{gap:18px!important}#box,#standalonepage #mainContent{width:100%!important}#top{background-repeat:no-repeat}@property --round{syntax:"<percentage>";inherits:false;initial-value:-50%}[data-group]:before{--round:-50%;content:"";height:calc(100% - 1px);transform:translate(-100%,round(down,-50%,1px));transform:translate(-100%,var(--round));z-index:2;border:2px solid #fff;border-right:none;width:3px;position:absolute;top:0;left:0}[data-group="1"]:before{border-color:#3f51b5}[data-group="2"]:before{border-color:#2196f3}[data-group="3"]:before{border-color:#009688}[data-group="4"]:before{border-color:#43a047}[data-group="5"]:before{border-color:#7cb342}[data-group="6"]:before{border-color:#fdd835}[data-group="7"]:before{border-color:#fb8c00}[data-group="8"]:before{border-color:#e53935}[data-group="9"]:before{border-color:#ec407a}[data-group="10"]:before{border-color:#5e35b1}[data-group="11"]:before{border-color:#795548}[data-group="12"]:before{border-color:#607d8b}.planetBarSpaceObjectContainer{margin:0!important;top:0!important;left:0!important}.planetBarSpaceObjectHighlightContainer{width:0!important;height:0!important;display:none!important}div#bannerSkyscrapercomponent{margin-left:300px!important}#planetbarcomponent #myPlanets,#planetbarcomponent #myWorlds{width:208px!important}#planetbarcomponent #countColonies{display:none}#planetbarcomponent #rechts{margin-top:-50px!important;margin-bottom:0!important}.ogl_topbar{background:var(--tertiary);z-index:11;-webkit-border-radius:3px;border-radius:3px;align-content:space-evenly;justify-content:space-evenly;align-items:center;height:30px;margin-bottom:3px;display:flex;position:relative;box-shadow:0 0 20px -5px #000,0 0 0 1px #17191c}.ogl_topbar i,.ogl_topbar a{text-decoration:none;color:#737ca9!important;font-size:17px!important}.ogl_topbar .ogl_active{animation:1s infinite spin}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(-360deg)}}.ogl_topbar>:first-child:hover{color:#dbc453!important}.ogl_topbar>:nth-child(2):hover{color:#4bbbd5!important}.ogl_topbar>:nth-child(3):hover{color:#e17171!important}.ogl_topbar>:nth-child(4):hover{color:#76d19a!important}.ogl_topbar>:nth-child(5):hover{color:#a1aac9!important}.ogl_topbar>:nth-child(6):hover{color:#fd7db8!important}.ogl_topbar>:nth-child(7):hover{color:#fff!important}.ogl_topbar .ogl_button{white-space:nowrap;z-index:10000000;border:none;width:80%;height:80%;display:none;position:absolute;top:9%;right:2%;box-shadow:-5px 0 8px rgba(0,0,0,.65),inset 0 0 15px rgba(99,125,159,.39)}.ogl_initHarvest .ogl_topbar .ogl_button{display:block}#planetList{box-shadow:none;grid-gap:3px;background:#0a121a;-webkit-border-radius:5px;border-radius:5px;padding:2px;display:grid;position:relative}.smallplanet{grid-gap:2px;grid-template-columns:67% auto;display:grid;width:100%!important;height:39px!important;margin:0!important}.planetlink,.moonlink{box-sizing:border-box;background:linear-gradient(45deg,#283645,#171c24);-webkit-border-radius:9px;border-radius:9px;background-position:0!important;height:100%!important;position:relative!important;top:0!important;left:0!important;overflow:hidden!important}.planetlink.active,.moonlink.active{background:linear-gradient(45deg,#24aeff,#4b4bd9 80%)}.smallplanet a.alert{z-index:2!important;top:22px!important;left:-15px!important}body.ogl_destinationPicker .planetlink.active,body.ogl_destinationPicker .moonlink.active{opacity:.3;pointer-events:none;background:#05050a}.planetlink:hover{background:linear-gradient(45deg,#233a50,#334a62 80%)}.moonlink:hover{background:linear-gradient(45deg,#233a50,#334a62 80%)}.planetlink.ogl_currentDestination,.moonlink.ogl_currentDestination{background:linear-gradient(45deg,#ffc107,#b15f38 80%)}.planetlink.ogl_attacked,.moonlink.ogl_attacked{box-shadow:inset 0 0 6px 4px #c92020}.ogl_destinationPicker .smallplanet .ogl_currentDestination .ogl_available,.ogl_destinationPicker .smallplanet .ogl_currentDestination .ogl_refreshTimer{opacity:0!important}.ogl_destinationPicker .smallplanet .ogl_currentDestination:after{color:var(--ogl);content:"sports_score";text-shadow:1px 2px 4px #000;z-index:2;font-family:Material Icons;font-size:20px;position:absolute;top:50%;transform:translateY(-50%)}.ogl_destinationPicker .smallplanet .ogl_currentDestination:after{text-align:right;right:2px}.smallplanet .planet-name,.smallplanet .planet-koords{text-shadow:0 0 6px #000,1px 1px 6px rgba(0,0,0,.5)!important;font-family:Arial,Helvetica,sans-serif!important;font-weight:700!important;left:22px!important;overflow:visible!important}.smallplanet .planet-name{-webkit-border-radius:3px;border-radius:3px;color:#b1cdff!important;max-width:42%!important;font-size:11px!important;top:6px!important}.smallplanet .planet-name:before{content:"";filter:blur(4px);opacity:.9;z-index:-1;background:#293a4c;-webkit-border-radius:50%;border-radius:50%;display:block;position:absolute;top:-1px;bottom:-1px;left:-7px;right:-7px}.smallplanet .planet-koords:before{content:"";filter:blur(4px);opacity:.9;z-index:-1;background:#293a4c;-webkit-border-radius:50%;border-radius:50%;display:block;position:absolute;top:-1px;bottom:-1px;left:-7px;right:-7px}.smallplanet .planetlink.active .planet-name{color:#b1cdff!important}.smallplanet .planetlink.active:not(:hover) .planet-name:before{opacity:.3;background:#3f86f1}.smallplanet .planetlink.active:not(:hover) .planet-koords:before{opacity:.3;background:#3f86f1}.smallplanet .planetlink:hover .planet-name:before{opacity:.5}.smallplanet .planetlink:hover .planet-koords:before{opacity:.5}.smallplanet .planetlink.ogl_currentDestination .planet-name{color:#ffea81!important}.smallplanet .planetlink.ogl_currentDestination .planet-name:before{opacity:.5;background:#4e3114}.smallplanet .planetlink.ogl_currentDestination .planet-koords:before{opacity:.5;background:#4e3114}.smallplanet .planet-koords{color:#fff!important;font-size:12px!important;top:21px!important}.smallplanet .wreckFieldIcon{transform:translate(-100%);position:absolute!important;top:auto!important;bottom:auto!important;left:0!important;right:auto!important}.smallplanet .wreckFieldIcon .material-icons{color:var(--ogl);text-shadow:2px 1px #102742;position:relative;top:5px;left:5px;font-size:12px!important}.ogl_wreckfieldIcon .icon{filter:sepia()hue-rotate(345deg)saturate(300%)}.ogl_wreckfieldIcon.ogl_ok .icon{filter:sepia()hue-rotate(63deg)saturate(350%)}.smallplanet .wreckFieldIcon:hover .material-icons{filter:brightness(1.4)}.smallplanet .wreckFieldIcon.ogl_ok .material-icons{color:#24f38a}.smallplanet .ogl_available{box-sizing:border-box;text-align:right;text-shadow:1px 1px 4px #000;align-items:center;height:100%;padding:1px 0;font-size:10px;font-weight:700;line-height:10px;display:grid;position:absolute;top:0;right:3px}.smallplanet .ogl_available:before{content:"";opacity:.2;background:#000;width:100%;height:100%;position:absolute;top:0;left:0;box-shadow:0 0 10px 10px #000}.smallplanet .ogl_refreshTimer{pointer-events:none;background:#0a131b;-webkit-border-radius:0 9px 0 0;border-radius:0 9px 0 0;width:15px;padding:0 2px;font-size:10px;font-weight:700;line-height:17px;position:absolute;bottom:-3px;left:-2px}.smallplanet .ogl_refreshTimer.ogl_moon{left:67%}#planetList.ogl_alt .smallplanet .ogl_refreshTimer{display:none!important}.smallplanet .planetPic{width:50px;height:50px;top:0;left:4px}.smallplanet .planetBarSpaceObjectContainer{height:100%!important}.smallplanet .icon-moon{width:32px;height:32px;bottom:-2px;left:-6px;top:auto!important}.smallplanet .ogl_sideIconInfo,.smallplanet .ogl_sideIconTop,.smallplanet .ogl_sideIconBottom{gap:5px;display:flex;position:absolute;left:calc(100% + 6px);font-size:12px!important}.smallplanet .ogl_sideIconTop{top:-1px}.smallplanet .ogl_todoIcon:after{content:attr(data-list);font-family:Verdana,Arial,SunSans-Regular,sans-serif;font-size:12px;font-weight:700}.smallplanet .ogl_fleetIcon:after{content:attr(data-list);font-family:Verdana,Arial,SunSans-Regular,sans-serif;font-size:12px;font-weight:700}.smallplanet .ogl_fleetIcon:before{text-indent:-1px;font-size:16px!important}.smallplanet .ogl_todoIcon{gap:1px;font-size:14px!important}.smallplanet .ogl_sideIconInfo>div{color:#b3c6d3;align-items:center;display:flex!important}.smallplanet .ogl_sideIconTop>div{color:#b3c6d3;align-items:center;display:flex!important}.smallplanet .ogl_sideIconBottom>div{color:#b3c6d3;align-items:center;display:flex!important}.smallplanet .ogl_sideIconInfo>div:hover{color:var(--ogl)}.smallplanet .ogl_sideIconTop>div:hover{color:var(--ogl)}.smallplanet .ogl_sideIconBottom>div:hover{color:var(--ogl)}.smallplanet .ogl_sideIconBottom{top:14px}.smallplanet .ogl_sideIconBottom .ogl_fleetIcon:before{transform:scaleX(-1)}.smallplanet .ogl_sideIconInfo{top:28px}.smallplanet .ogl_jumpgateTimer{font-size:11px}.smallplanet .ogl_sideIconInfo .material-icons,.smallplanet .ogl_sideIconTop .material-icons,.smallplanet .ogl_sideIconBottom .material-icons{cursor:pointer}.msg{outline:1px solid #000;position:relative;overflow:hidden;background:var(--tertiary)!important}.msg[data-msgType] .msg_status:before{background:0 0!important}.msg[data-msgType="expe"] .msg_status{background:var(--mission15)!important}.msg[data-msgType="discovery"] .msg_status{background:var(--lifeform)!important}.msg_new{background:linear-gradient(#2e525e,#223644 6%,#172834 20%)!important}.msg_title .ogl_mainIcon{color:var(--ogl)!important}.msg_title .ogl_ptre{color:#ff942c!important}.ogl_battle{grid-gap:6px;text-align:center;text-transform:capitalize;width:fit-content;background:rgba(0,0,0,.15);border:2px solid #323d4e;flex-wrap:wrap;justify-content:center;align-items:center;width:-moz-fit-content;margin:8px auto;padding:3px 6px;font-weight:700;display:flex;position:relative;box-shadow:0 0 6px -2px #000;color:#48566c!important}.ogame-tracker-msg .ogl_battle{display:none!important}.ogl_battleTooltip{font-size:14px!important}[data-depletion]:after{color:#eb5656;content:"\\f164";font-family:Material Icons;font-size:16px;font-weight:400}[data-depletion="1"]:after{color:#48566c;content:"\\f165"}[data-depletion="2"]:after{color:#ebb208;content:"\\f14f";transform:scaleX(-1)}[data-depletion="3"]:after{color:#f58725;content:"\\f166"}.ogl_battle[data-resultType][data-size="0"]{border-image:linear-gradient(to bottom right,#ede07c,#744407,#ede07c,#744407) 1!important}.ogl_battle[data-resultType][data-size="1"]{border-image:linear-gradient(to bottom right,#d7d7d7,#525252,#d7d7d7,#525252) 1!important}[data-size-value]{font-weight:700}[data-size-depletion]{color:#eb5656!important}[data-size-depletion="1"]{color:#48566c!important}[data-size-depletion="2"]{color:#ebb208!important}[data-size-depletion="3"]{color:#f58725!important}[data-size-value="0"]{color:#ede07c!important}[data-size-value="1"]{color:#ddd!important}[data-size-value="2"]{color:#d17755!important}[data-resultType]:before{content:"";font-family:Material Icons;font-size:18px;display:block;font-weight:400!important}[data-resultType="raid"]:before{content:"\\f14a"}[data-resultType="battle"]:before{content:"\\f14a"}[data-resultType="resource"]:before{content:"\\f13f"}[data-resultType="darkmatter"]:before{content:"\\f13f"}[data-resultType="artefact"]:before{content:"\\f168"}[data-resultType="ship"]:before{content:"\\f119"}[data-resultType="other"]:before{content:"\\e9d0"}[data-resultType="nothing"]:before{content:"\\f106"}[data-resultType*="lifeform"]:before{content:"\\f12c"}[data-resultType*="item"]:before{content:"\\f15b"}[data-resultType*="debris"]:before{content:"\\f160"}[data-resultType*="cargo"]:before{content:"\\f13f"}[data-resultType*="early"]:before{content:"\\f13a"}[data-resultType*="late"]:before{content:"\\f13a"}[data-resultType="duration"]:before{content:"\\f13a"}[data-resultType*="blackhole"]:before{content:"\\f13b"}[data-resultType*="trader"]:before{content:"\\f15d"}[data-resultType="alien"]:before{content:"\\f15a"}[data-resultType="pirate"]:before{content:"\\f15c"}[data-resultType="alien"]{color:var(--alien)!important}[data-resultType="pirate"]{color:var(--pirate)!important}[data-resultType="battle"]{color:var(--pirate)!important}[data-resultType="blackhole"]{color:var(--blackhole)!important}[data-resultType="trader"]{color:var(--trader)!important}[data-resultType="item"]{color:var(--item)!important}[data-resultType="early"]{color:var(--early)!important}[data-resultType="late"]{color:var(--late)!important}[data-resultType="duration"]{color:var(--late)!important}[data-resultType="resource"]{color:var(--resource)!important}[data-resultType="ship"]{color:var(--ship)!important}[data-resultType="dm"]{color:var(--dm)!important}[data-resultType="darkmatter"]{color:var(--dm)!important}[data-resultType="lifeform"]:after{color:#fff;content:"XP";align-self:baseline;margin-left:3px;font-size:smaller;display:block}.ogl_notification .ogl_icon[class*=lifeform]:after{color:#fff;content:"XP";align-self:baseline;margin-left:3px;font-size:smaller;display:block}.ogl_battle[data-resultType]:before{color:#48566c!important}.ogl_battle.ogl_clickable:hover{cursor:pointer;border:2px solid var(--ogl)!important}.ogl_battle .ogl_icon{background:0 0;align-items:center;padding:0;line-height:16px;display:flex}.ogl_battle .ogl_icon:not(:last-child){margin-right:20px}.ogl_battle[data-resultType="ship"] .ogl_icon{color:#98b1cb;grid-gap:3px;display:grid}.ogl_battle[data-resultType="global"] .ogl_icon{color:#98b1cb;grid-gap:3px;display:grid}.ogl_battle[data-resultType="ship"] .ogl_icon:not(:last-child){margin-right:7px}.ogl_battle[data-resultType="global"] .ogl_icon:not(:last-child){margin-right:0}.ogl_battle .ogl_icon:before{image-rendering:auto;background-size:400px;-webkit-border-radius:0;border-radius:0;width:32px;height:20px;margin:0 5px 0 0;display:block}.ogl_battle[data-resultType="raid"] .ogl_icon{display:grid}.ogl_battle[data-resultType="raid"] .ogl_icon:before{grid-row:1/3}.ogl_battle[data-resultType="raid"] .ogl_icon>span:last-child{grid-area:2/2}.ogl_battle[data-resultType="ship"] .ogl_icon:before{margin:auto}.ogl_battle[data-resultType="global"] .ogl_icon:before{margin:auto}.ogl_battle .ogl_icon[class*=ogl_2]:before{background-size:40px}.ogl_battle .ogl_icon.ogl_artefact:before{background-position:59% 28%;background-size:50px}.ogl_battle .ogl_icon.ogl_lifeform1:before{background-position:1px 76%}.ogl_battle .ogl_icon.ogl_lifeform2:before{background-position:11% 76%}.ogl_battle .ogl_icon.ogl_lifeform3:before{background-position:22% 76%}.ogl_battle .ogl_icon.ogl_lifeform4:before{background-position:32% 76%}.ogl_expeRecap{grid-gap:8px;background:#14181f;width:auto;padding:10px 0 6px;font-size:11px;position:relative}.ogl_expeRecap:before{margin-left:0!important}.ogl_expeRecap:after{background:var(--blue);color:#fff;content:attr(data-count);text-transform:lowercase;-webkit-border-radius:50px;border-radius:50px;padding:4px 5px;font-size:10px;position:absolute;top:-3px;right:-3px;box-shadow:0 0 6px -2px #000}#messages .tab_favorites,#messages .tab_inner{background-size:410px;background:#030406!important}.ogl_deleted{color:var(--red);opacity:.5}.ogl_spytable{color:#93b3c9;counter-reset:spy;counter-increment:spy;user-select:none;background:#12161a;-webkit-border-radius:5px;border-radius:5px;width:100%;margin:40px 0 10px;padding:5px;font-size:11px}.ogl_spytable:not(:has(.ogl_spyLine:not(.ogl_spySum))){display:none!important}#messagecontainercomponent:has(.active:not([data-subtab-id="20"])) .ogl_spytable{display:none!important}#messagecontainercomponent:has(.ogl_boardMessageTab.marker) .ogl_spytable{display:none!important}.ogl_spytable .ogl_spytableSettings{justify-content:right;align-items:center;display:flex}.ogl_spytable.ogl_outdated .ogl_spytableSettings:before{color:var(--ogl);content:"\\f10e";font-family:Material Icons;animation:1s infinite spin;font-size:16px!important}.ogl_spytable .ogl_spytableSettings [data-label]:before{content:attr(data-label);color:#fff;text-shadow:1px 1px #000;background:#4466a3;-webkit-border-radius:4px;border-radius:4px;padding:0 4px;font-family:monospace;font-size:12px;line-height:14px;display:block;position:absolute;top:8px;right:-2px}.ogl_spytable .ogl_spytableSettings>div{float:right;background:0 0;border:none;height:20px;padding:0 6px;font-size:18px!important;line-height:20px!important}.ogl_spytable .ogl_spytableSettings>div:hover{color:#fff!important}.ogl_spytable .ogl_spytableSettings [data-action=ignore]{color:var(--red)!important}.ogl_spytable .ogl_spytableSettings [data-action=highlight]{color:var(--ogl)!important}.ogl_spytable .ogl_spytableSettings [data-action=broom]{font-size:14px!important}.ogl_spyTableRules .ogl_addRule{grid-gap:10px;background:#191f2a;border:2px solid #2f384a;-webkit-border-radius:3px;border-radius:3px;align-items:center;padding:16px;display:flex}.ogl_spyTableRules .ogl_addRule select,.ogl_spyTableRules .ogl_addRule input,.ogl_spyTableRules .ogl_addRule button{height:26px!important;line-height:26px!important}.ogl_spyTableRules .ogl_addRule .ogl_button{padding:0 8px!important}.ogl_spyTableRules legend{grid-gap:5px;align-items:center;display:flex}.ogl_spyTableRules legend .material-icons{font-size:23px!important}.ogl_rulesList{grid-gap:5px;margin-top:20px;display:grid}.ogl_rulesList>div{background:var(--secondaryReversed);-webkit-border-radius:3px;border-radius:3px;grid-template-columns:40px 200px 30px auto 30px 50px;align-items:center;padding-left:10px;display:grid}.ogl_rulesList>div:first-child:before{content:""}.ogl_rulesList>div:not(:first-child):before{content:"OR";color:#5e6a7c;font-size:10px}.ogl_rulesList .ogl_danger{font-size:16px!important}#fleetsTab .ogl_spytable{margin-top:55px;margin-bottom:-25px}.ogl_spytable a.ogl_important span{color:#fff!important}.ogl_spytable hr{background:#1e252e;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_spytable .ogl_spyIcon{font-size:16px!important}.ogl_spytable a:not(.ogl_button):not([class*=status_abbr]){color:inherit!important}.ogl_spytable [data-galaxy]:not(.ogl_button){color:inherit!important}.ogl_spytable a:hover{text-decoration:underline!important}.ogl_spytable [data-galaxy]:hover{text-decoration:underline!important}.ogl_spyHeader{grid-gap:3px;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:22px 34px 30px 24px 96px auto 70px 43px 43px 130px;align-items:center;margin-bottom:2px;display:grid}.ogl_spytable .ogl_spyLine>div:not(.ogl_more){grid-gap:3px;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:22px 34px 30px 24px 96px auto 70px 43px 43px 130px;align-items:center;margin-bottom:2px;display:grid}.ogl_spytable .ogl_spyLine:not(:first-child){counter-increment:spy}.ogl_spytable .ogl_spyLine>div>*{background:var(--secondary);text-overflow:ellipsis;white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;align-items:center;height:24px;padding:0 4px;display:flex;position:relative;overflow:hidden}.ogl_spytable .ogl_spyLine>div>a{text-decoration:none}.ogl_spytable .ogl_spyLine>div>span:nth-child(5){justify-content:right}.ogl_spytable>div>span:nth-child(6){justify-content:right}.ogl_spytable>div>span:nth-child(7){justify-content:right}.ogl_spytable .ogl_spyLine:not(.ogl_spySum)>div>span:first-child:before{content:counter(spy)}.ogl_spytable .msg_action_link{text-overflow:ellipsis;overflow:hidden;padding:0!important}.ogl_spytable .ogl_fleetIcon{pointer-events:none;text-shadow:1px 1px 3px #000;position:absolute;bottom:-2px;left:1px}.ogl_spytable .ogl_spyLine>div>span a{text-decoration:none}.ogl_spytable .ogl_spyLine a:not(.ogl_button):hover{color:#fff!important;cursor:pointer!important;text-decoration:underline!important}.ogl_spytable .ogl_spyLine [data-galaxy]:hover{color:#fff!important;cursor:pointer!important;text-decoration:underline!important}.ogl_spytable .ogl_spyHeader b{color:#3c4f5a;background:#12161a;-webkit-border-radius:3px;border-radius:3px;padding-left:4px;font-size:11px!important;line-height:27px!important}.ogl_spytable .ogl_spyHeader b.material-icons{font-size:14px!important}.ogl_spytable .ogl_spyHeader b:first-child{padding-left:0}.ogl_spytable .ogl_spyHeader b:nth-child(3){padding-left:0}.ogl_spytable .ogl_spyHeader b:last-child{background:0 0;padding:0}.ogl_spytable .ogl_spyHeader span:last-child{background:0 0;padding:0}.ogl_spytable .ogl_spyHeader [data-filter].ogl_active{color:var(--amber)}.ogl_spytable [data-title]:not(.ogl_spyIcon):not([class*=status_abbr]){color:inherit!important}.ogl_spytable [data-filter]:after{color:#3c4f5a;content:"\\f15f";float:right;font-family:Material Icons;font-size:16px}.ogl_spytable .ogl_spyHeader [data-filter]:hover{color:#fff;cursor:pointer}.ogl_spytable .ogl_actions{grid-gap:2px;justify-content:space-between;font-size:16px;background:0 0!important;-webkit-border-radius:0!important;border-radius:0!important;padding:0!important}.ogl_spytable .ogl_type>*{color:#b7c1c9;font-size:16px!important}.ogl_spytable .ogl_type>:hover{color:#fff}.ogl_spytable .ogl_actions .ogl_button{border:none;width:100%;padding:0;height:24px!important;line-height:24px!important;text-decoration:none!important}.ogl_spytable .ogl_actions>:not(.material-icons){font-size:12px;font-weight:700}.ogl_spytable .ogl_reportTotal{text-decoration:none}.ogl_spytable .ogl_actions a:hover{text-decoration:none}.ogl_spyLine .ogl_more{background:var(--primary);-webkit-border-radius:3px;border-radius:3px;margin-bottom:3px;padding:7px}.ogl_spyLine .ogl_more .ogl_icon{align-items:center;display:flex}.ogl_spyLine .ogl_more>div{grid-gap:5px;grid-template-columns:repeat(auto-fit,minmax(0,1fr));align-items:center;margin-bottom:5px;display:grid}.ogl_spyLine .ogl_more>div>*{background:var(--secondary);-webkit-border-radius:3px;border-radius:3px;padding:2px;line-height:20px;text-decoration:none}.ogl_spyLine .ogl_more a:hover{color:#fff}.ogl_spyLine .ogl_spyTableName{background:var(--secondary);align-items:center;height:100%;display:flex}.ogl_spyLine .ogl_spyTableName a{text-overflow:ellipsis;white-space:nowrap;align-items:center;width:86%;height:100%;text-decoration:none;display:flex;overflow:hidden}.ogl_trashCounterSpy{width:28px;position:absolute;top:48px;right:104px;min-width:0!important;padding:0!important;font-size:16px!important;line-height:26px!important;display:block!important}.galaxyTable{background:#10151a!important}#galaxycomponent .systembuttons img{pointer-events:none}#galaxyContent .ctContentRow .galaxyCell{background:var(--secondary)!important;-webkit-border-radius:2px!important;border-radius:2px!important}#galaxyContent .cellPlanetName,#galaxyContent .cellPlayerName{padding:0 5px;justify-content:left!important}#galaxyContent .cellPlanetName span{text-overflow:ellipsis;white-space:nowrap;max-width:62px;overflow:hidden}#galaxyContent .cellPlayerName{flex-basis:106px!important}#galaxyContent .cellPlayerName .tooltipRel:hover{text-decoration:underline}#galaxyContent .cellPlayerName [rel]{text-overflow:ellipsis;white-space:nowrap;max-width:110px;line-height:28px;overflow:hidden;display:inline-block!important}#galaxyContent .cellPlayerName pre{display:none}.ogl_ranking{text-decoration:none!important}#galaxyContent .ogl_ranking{color:#7e95a9;cursor:pointer}#galaxyContent .ogl_ranking:hover{color:#fff}#galaxyContent .ogl_ranking a{color:inherit;text-decoration:none}#galaxyHeader .btn_system_action{max-width:100px;overflow:hidden}#galaxyContent .cellPlayerName [class*=status_abbr]{margin-right:auto}#galaxyContent .ownPlayerRow{cursor:pointer}#galaxyContent .ctContentRow .cellDebris a{text-align:center;white-space:nowrap;line-height:30px;text-decoration:none}#galaxyContent .ctContentRow .cellDebris.ogl_important a{color:#fff!important}[class*=filtered_filter_]{opacity:1!important}#galaxyContent .ctContentRow[class*=filtered_filter_] .galaxyCell:not(.ogl_important){background:#12181e!important}#galaxyContent .expeditionDebrisSlotBox{background:var(--primary)!important}#galaxyContent .expeditionDebrisSlotBox .material-icons{color:#48566c;font-size:20px!important}#galaxyContent .ctContentRow .galaxyCell.cellDebris.ogl_important,#galaxyContent .ogl_expeditionRow.ogl_important{background:linear-gradient(192deg,#a96510,#6c2c0d 70%)!important}.ogl_spytable .ogl_spyLine:not(.ogl_ignored) .ogl_important{background:linear-gradient(192deg,#a96510,#6c2c0d 70%)!important}.ogl_spytable .ogl_ignored{opacity:.2}.ogl_spytable .ogl_ignored.ogl_highlighted{opacity:.5}.ogl_spytable .ogl_highlighted>div:not(.ogl_more)>:not(.ogl_actions){background:linear-gradient(192deg,#3d4757,#2a2439 70%)}.ogl_spytable .ogl_highlighted>div:not(.ogl_more)>.ogl_textRight{font-weight:700;color:var(--ogl)!important}#galaxyContent .ogl_expeditionRow.ogl_important .material-icons{color:#bb6848}[class*=filtered_filter_]>.cellPlanet:not(.ogl_important) .microplanet{opacity:.2!important}[class*=filtered_filter_]>.cellPlanetName:not(.ogl_important) span:not(.icon){opacity:.2!important}[class*=filtered_filter_]>.cellMoon:not(.ogl_important) .micromoon{opacity:.2!important}[class*=filtered_filter_]>.cellPlayerName:not(.ogl_important) span{opacity:.2!important}[class*=filtered_filter_]>.cellPlayerName:not(.ogl_important) .ogl_ranking{opacity:.2!important}[class*=filtered_filter_]>.cellAlliance:not(.ogl_important) span{opacity:.2!important}[class*=filtered_filter_]>.cellAction:not(.ogl_important) a:not(.planetDiscover):not(.planetMoveIcons){opacity:.2!important}.ogl_popup{opacity:0;pointer-events:none;z-index:1000001;background:rgba(0,0,0,.85);flex-direction:column;justify-content:center;align-items:center;width:100dvw;height:100dvh;transition:opacity .3s,pointer-events .3s;display:flex;position:fixed;top:0;left:0}.ogl_popup.ogl_active{pointer-events:all;opacity:1}.ogl_popup .ogl_close,.ogl_popup .ogl_share{color:#556672;cursor:pointer;text-align:center;width:30px;position:absolute;top:2px;right:0;font-size:18px!important;line-height:30px!important}.ogl_popup .ogl_close:hover{color:#fff}.ogl_popup .ogl_share:hover{color:#fff}.ogl_popup .ogl_share{top:30px;font-size:16px!important}.ogl_popup>.ogl_popupContent{background:var(--primary);background:#0f1218;-webkit-border-radius:3px;border-radius:3px;max-width:980px;max-height:80%;padding:30px;animation:.15s pop;position:relative;overflow-x:hidden;overflow-y:auto}.ogl_popup h2{color:#9dbddd;text-align:center;border-bottom:2px solid #161b24;margin-bottom:16px;padding-bottom:7px;font-size:14px}@keyframes pop{0%{opacity:0;transform:translateY(-30px)}to{opacity:1;transform:translateY(0)}}.ogl_keeper{max-width:700px!important}.ogl_keeper .ogl_limiterLabel{float:left;width:100px;margin-right:20px}.ogl_keeper .ogl_limiterLabel input{margin-left:auto}.ogl_keeper hr{background:#1e252e;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_resourceLimiter,.ogl_shipLimiter,.ogl_jumpgateLimiter{grid-gap:5px 18px;background:#1b202a;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:repeat(12,1fr);padding:12px;display:grid;position:relative}.ogl_shipLimiter,.ogl_jumpgateLimiter{grid-template-columns:repeat(20,1fr)}.ogl_keeper .ogl_icon{grid-column:span 4;padding:0}.ogl_keeper .ogl_metal,.ogl_keeper .ogl_crystal,.ogl_keeper .ogl_deut,.ogl_keeper .ogl_food{grid-column:span 3}.ogl_keeper .ogl_icon:before{vertical-align:text-bottom;margin-right:5px!important}.ogl_keeper input{box-sizing:border-box;color:inherit;background:#121518;border:none;border-top:1px solid #080b10;border-bottom:1px solid #242a32;-webkit-border-radius:3px;border-radius:3px;width:calc(100% - 34px);padding:4px 6px}.ogl_keeper .ogl_button{background:var(--secondary);color:#fff;cursor:pointer;-webkit-border-radius:3px;border-radius:3px;line-height:24px!important}.ogl_keeper .ogl_button.ogl_active{background:var(--highlight)}.ogl_keeper .ogl_button:last-child{grid-column:-2}.ogl_keeper .ogl_profileTabs{grid-gap:0 5px;grid-column:1/-1;grid-template-columns:repeat(5,1fr);display:grid}.ogl_keeper input.ogl_title{text-align:center;grid-column:1/-1;width:100%;padding:8px}.ogl_keeper h2{grid-column:1/-1}.ogl_keeper h2:not(:nth-child(2)){margin:20px 0 10px}.ogl_keeper .ogl_missionPicker{grid-gap:4px;grid-column:1/-1;grid-template-columns:repeat(11,auto);justify-content:end;margin-top:10px;display:grid}.ogl_keeper .ogl_missionPicker [data-mission]{filter:grayscale()}.ogl_keeper .ogl_missionPicker [data-mission]:hover{cursor:pointer;filter:grayscale(.5)}.ogl_keeper .ogl_missionPicker .ogl_active{box-shadow:none!important;filter:grayscale(0)!important}.ogl_side{background:var(--primary);box-sizing:border-box;z-index:1000000;width:385px;height:100%;padding:40px 18px 18px;transition:transform .3s;position:fixed;top:0;right:0;overflow:auto;transform:translate(100%);box-shadow:0 0 50px #000}.ogl_side.ogl_active{transform:translate(0%);box-shadow:0 0 50px #000}.ogl_side .ogl_close,.ogl_side .ogl_back{color:#556672;cursor:pointer;position:absolute;top:10px;right:20px;font-size:28px!important}.ogl_side .ogl_close:hover{color:#fff}.ogl_side .ogl_back:hover{color:#fff}.ogl_side .ogl_back{left:20px;right:auto}.ogl_side hr{background:#151e28;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_side h2{color:#7e8dab;justify-content:center;align-items:center;margin-bottom:20px;font-size:14px;display:flex}.ogl_side h2 .ogl_flagPicker{height:17px;margin-left:5px}.ogl_side h2 i{margin-left:10px}.ogl_config{grid-gap:8px;line-height:26px;display:grid}.ogl_config label{color:#c7c7c7;background:linear-gradient(-207deg,#0d1014,#212b34);-webkit-border-radius:3px;border-radius:3px;align-items:center;margin:2px 0;padding:0;display:flex}.ogl_config label:before{content:attr(data-label);display:block}.ogl_config label.tooltipLeft:before{text-decoration:underline dotted}.ogl_config label>:first-child{margin-left:auto}.ogl_inputField{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_config label>input[type=text]{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_config label>input[type=password]{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_config label>input[type=checkbox]{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_config label>select{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_todoList input[type=checkbox]{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_limiterLabel input[type=checkbox]{box-sizing:border-box!important;visibility:visible!important;background:#121518!important;border:1px solid #080b10!important;-webkit-border-radius:3px!important;border-radius:3px!important;height:22px!important;padding:0 5px!important;font-size:12px!important;box-shadow:inset 0 2px 3px #0b0e12!important}.ogl_config label>input[type=text]{color:#5d738d!important}.ogl_config label>input[type=password]{color:#5d738d!important}.ogl_config label>input[type=checkbox]{color:#5d738d!important}.ogl_config label>select{color:#5d738d!important}.ogl_inputField:not(.ogl_metal):not(.ogl_crystal):not(.ogl_deut):not([type=checkbox]){color:#5d738d!important}.ogl_todoList input[type=checkbox]{color:#5d738d!important}.ogl_limiterLabel input[type=checkbox]{color:#5d738d!important}.ogl_config label>input[type=text]{width:105px!important}.ogl_config label>input[type=password]{width:105px!important}.ogl_config label>select{width:105px!important}.ogl_config label>input[type=checkbox]{appearance:none!important;color:var(--ogl)!important;cursor:pointer!important;justify-content:center!important;align-items:center!important;width:16px!important;height:16px!important;display:flex!important}.ogl_todoList input[type=checkbox]{appearance:none!important;color:var(--ogl)!important;cursor:pointer!important;justify-content:center!important;align-items:center!important;width:16px!important;height:16px!important;display:flex!important}.ogl_limiterLabel input[type=checkbox]{appearance:none!important;color:var(--ogl)!important;cursor:pointer!important;justify-content:center!important;align-items:center!important;width:16px!important;height:16px!important;display:flex!important}.ogl_inputField[type=checkbox]{appearance:none!important;color:var(--ogl)!important;cursor:pointer!important;justify-content:center!important;align-items:center!important;width:16px!important;height:16px!important;display:flex!important}.ogl_config label>input[type=checkbox]:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_todoList input[type=checkbox]:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_limiterLabel input[type=checkbox]:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_inputField[type=checkbox]:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_config label>input[type=checkbox]:checked:before{content:"\\f103";pointer-events:none;font-family:Material Icons;font-size:18px!important}.ogl_todoList input[type=checkbox]:checked:before{content:"\\f103";pointer-events:none;font-family:Material Icons;font-size:18px!important}.ogl_limiterLabel input[type=checkbox]:checked:before{content:"\\f103";pointer-events:none;font-family:Material Icons;font-size:18px!important}.ogl_inputField[type=checkbox]:checked:before{content:"\\f103";pointer-events:none;font-family:Material Icons;font-size:18px!important}.ogl_config .ogl_icon[class*=ogl_2]{cursor:pointer;padding:0}.ogl_config .ogl_icon[class*=ogl_mission]{cursor:pointer;padding:0}.ogl_config .ogl_icon[class*=ogl_2]:not(:first-child){margin-left:5px}.ogl_config .ogl_icon[class*=ogl_mission]:not(:first-child){margin-left:5px}.ogl_config .ogl_icon[class*=ogl_2]:hover:before{box-shadow:0 0 0 2px var(--ogl)}.ogl_config .ogl_icon[class*=ogl_mission]:hover:before{box-shadow:0 0 0 2px var(--ogl)}.ogl_config .ogl_icon[class*=ogl_2].ogl_active:before{box-shadow:0 0 0 2px #fff}.ogl_config .ogl_icon[class*=ogl_mission].ogl_active:before{box-shadow:0 0 0 2px #fff}.ogl_config .ogl_icon[class*=ogl_2]:before{vertical-align:middle;margin:0}.ogl_config .ogl_icon[class*=ogl_mission]:before{vertical-align:middle;margin:0}.ogl_config .ogl_icon[class*=ogl_mission]:before{background-position-y:-6px!important;background-size:318px!important}.ogl_config [data-container]{background:#0e1116;-webkit-border-radius:3px;border-radius:3px;max-height:24px;padding:5px;transition:max-height .3s cubic-bezier(0,1,0,1);overflow:hidden}.ogl_config [data-container].ogl_active{max-height:400px;transition:max-height .3s ease-in-out}.ogl_config [data-container]>*{padding:0 7px}.ogl_config h3{color:#90aed5;cursor:pointer;text-align:left;text-transform:capitalize;user-select:none;-webkit-border-radius:3px;border-radius:3px;align-items:center;margin-bottom:5px;font-size:12px;display:flex;position:relative;overflow:hidden}.ogl_config [data-container] h3:hover{box-shadow:inset 0 0 0 2px var(--ogl);color:var(--ogl)}.ogl_config svg{color:inherit;fill:currentColor;height:26px;margin-right:5px;font-family:Material Icons;font-size:16px}.ogl_config>div h3:before{color:inherit;fill:currentColor;height:26px;margin-right:5px;font-family:Material Icons;font-size:16px}.ogl_config [data-container=fleet] h3:before{content:"\\f119"}.ogl_config [data-container=general] h3:before{content:"\\f111"}.ogl_config [data-container=interface] h3:before{content:"\\f10f"}.ogl_config [data-container=expeditions] h3:before{content:"\\f115"}.ogl_config [data-container=stats] h3:before{content:"\\f118"}.ogl_config [data-container=messages] h3:before{content:"\\f117"}.ogl_config [data-container=PTRE] h3:before{content:"\\f11d"}.ogl_config [data-container=data] h3:before{content:"\\f114"}.ogl_config h3:after{content:"\\f105";margin-left:auto;font-family:Material Icons}.ogl_config label button{color:#b7c1c9;cursor:pointer;text-shadow:1px 1px #000;background:linear-gradient(#405064,#2d3743 2px,#181e25);border:1px solid #17191c;-webkit-border-radius:3px;border-radius:3px;width:30px;position:relative;height:22px!important;font-size:16px!important;line-height:18px!important}.ogl_config label button.ogl_active{color:var(--ogl)}.ogl_config label button:hover{color:var(--ogl)}.ogl_config label .ogl_choice{color:#b7c1c9;cursor:pointer;text-align:center;background:linear-gradient(#405064,#2d3743 2px,#181e25);border-top:1px solid #17191c;border-bottom:1px solid #17191c;width:30px;font-weight:700;position:relative;height:20px!important;font-size:11px!important;line-height:20px!important}.ogl_config label .ogl_choice:first-child{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.ogl_config label .ogl_choice:last-child{-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.ogl_config label .ogl_choice.ogl_active{z-index:2;-webkit-border-radius:3px;border-radius:3px;box-shadow:0 0 0 2px #fff}.ogl_config label .ogl_choice:hover{color:var(--ogl)}.ogl_keyboardActions{grid-gap:5px 20px;grid-template-columns:repeat(2,1fr);display:grid}.ogl_keyboardActions h2{grid-column:1/-1}.ogl_keyboardActions label{background:var(--secondary);grid-gap:15px;grid-template-columns:auto 100px;align-items:center;padding-left:10px;display:grid}.ogl_keyboardActions label:hover{color:var(--amber);cursor:pointer}.ogl_keyboardActions label hr{appearance:none;border:none;height:1px;margin:0;padding:0}.ogl_keyboardActions input{box-shadow:none!important;color:#000!important;text-align:center!important;text-transform:uppercase!important;background:#fff!important;border:none!important;-webkit-border-radius:0!important;border-radius:0!important;height:21px!important;padding:4px!important;font-size:14px!important;font-weight:700!important;line-height:21px!important}.ogl_keyboardActions input:focus{outline:2px solid var(--amber);background:#ffe395!important}.ogl_keyboardActions button{cursor:pointer;grid-column:1/-1;margin-top:10px;line-height:30px!important}.ogl_planetList{color:#566c7c;margin-top:10px;font-size:11px}.ogl_planetList>div{grid-gap:3px;grid-template-columns:24px 70px 44px 44px auto;align-items:center;margin-bottom:3px;display:grid}.ogl_planetList>div>:nth-child(2){text-align:left;text-indent:5px}.ogl_planetList>div>:last-child{color:var(--date);font-size:10px}.ogl_planetList [class*=Icon]{font-size:10px}.ogl_planetList [class*=Icon]:before{vertical-align:bottom;margin-right:5px;font-size:16px}.ogl_filterColor{grid-gap:3px;grid-template-rows:repeat(1,1fr);grid-auto-flow:column;margin:10px 0;display:grid}.ogl_filterColor>*{cursor:pointer;-webkit-border-radius:50%;border-radius:50%;height:18px}label.ogl_off{opacity:.2}.ogl_filterColor>.ogl_off{opacity:.2}.ogl_filterColor>:hover{opacity:.7}label.ogl_off:hover{opacity:.7}.ogl_filterStatus{grid-gap:3px;grid-template-rows:repeat(1,1fr);grid-auto-flow:column;justify-content:end;margin:10px 0;display:grid}.ogl_filterStatus>*{cursor:pointer;text-align:center;background:#182b3b;-webkit-border-radius:4px;border-radius:4px;width:24px;line-height:24px}.ogl_filterStatus>.ogl_off{opacity:.2}.ogl_filterStatus>:hover{opacity:.7}.ogl_filterGalaxy,.ogl_filterSystem{color:#a0bacd;grid-gap:3px;text-align:center;grid-template-columns:repeat(10,1fr);font-size:11px;line-height:24px;display:grid}.ogl_filterGalaxy>*{cursor:pointer;background:#182b3b;-webkit-border-radius:4px;border-radius:4px}.ogl_filterSystem>*{cursor:pointer;background:#182b3b;-webkit-border-radius:4px;border-radius:4px}.ogl_filterGalaxy>:hover{color:#fff;text-decoration:underline}.ogl_filterSystem>:hover{color:#fff;text-decoration:underline}.ogl_filterGalaxy>.ogl_active:not(.ogl_disabled){color:#ccc;filter:brightness(1.4)}.ogl_filterSystem>.ogl_active:not(.ogl_disabled){color:#ccc;filter:brightness(1.4)}.ogl_filterGalaxy{margin-top:30px}.ogl_filterSystem{margin-top:10px}.ogl_watchList{grid-gap:3px;padding-top:40px;font-size:11px;display:grid}.ogl_watchList>div{grid-gap:3px;grid-template-columns:24px auto 100px 50px;display:grid}.ogl_watchList>div>*{background:#182b3b;-webkit-border-radius:3px;border-radius:3px;height:24px;padding:0 5px;line-height:24px}.ogl_watchList>div>:nth-child(2):hover{cursor:pointer;text-decoration:underline}.ogl_targetList{grid-gap:3px;padding-top:30px;font-size:11px;display:grid}.ogl_targetList .honorRank{vertical-align:sub;margin-right:1px;transform:scale(.75)}.ogl_targetList .ogl_target{color:#566c7c;grid-gap:3px;grid-template-columns:76px auto 24px 24px 24px 24px 24px;line-height:24px;display:grid;position:relative}.ogl_targetList .ogl_target>*{text-overflow:ellipsis;white-space:nowrap;background:#182b3b;-webkit-border-radius:3px;border-radius:3px;height:24px;overflow:hidden}.ogl_targetList .ogl_target [data-galaxy]{text-indent:17px}.ogl_targetList .ogl_target [class*=status_abbr_]{text-indent:3px}.ogl_targetList .ogl_target>:first-child{z-index:2;-webkit-border-radius:50%;border-radius:50%;align-self:center;width:7px;height:7px;display:block;position:absolute;left:6px}.ogl_targetList .ogl_target>*{grid-row:1}.ogl_targetList .ogl_target>[class*=Icon]:hover{color:#fff;cursor:pointer}.ogl_ogameDiv{background:var(--tertiary);-webkit-border-radius:0;border-radius:0;padding:2px;position:relative;box-shadow:0 0 20px -5px #000,0 0 0 2px #142030}.ogl_miniStats{cursor:pointer;-webkit-border-radius:3px;border-radius:3px;width:160px;margin-top:10px}.ogl_miniStats:hover:not(:has(.ogl_button:hover)){box-shadow:0 0 0 2px var(--ogl)}.ogl_miniStats>div{grid-gap:5px 0;grid-template-columns:repeat(3,1fr);justify-content:center;padding:3px 2px;font-size:11px;display:grid}.ogl_miniStats .ogl_header{user-select:none;height:18px;padding:5px;line-height:18px}.ogl_miniStats .ogl_header span{text-transform:capitalize;line-height:15px;display:inline-block}.ogl_miniStats .ogl_header div{color:#fff;cursor:pointer;z-index:1}.ogl_miniStats .ogl_header div:first-child{position:absolute;left:6px}.ogl_miniStats .ogl_header div:last-child{position:absolute;right:2px}.ogl_miniStats .ogl_icon{background:var(--secondary);grid-gap:3px;text-align:center;justify-content:center;align-items:center;margin:0 2px;padding:3px 0;display:grid}.ogl_miniStats .ogl_icon:before{height:20px;margin:auto}.ogl_miniStats .ogl_artefact:before{background-size:23px}.ogl_stats{display:grid}.ogl_stats h3{color:#97a7c5;text-align:center;grid-column:1/-1;margin-top:20px;font-size:11px;font-weight:700}.ogl_statsMonth{grid-gap:5px;align-items:center;display:flex}.ogl_statsMonth>*{padding:0 10px}.ogl_statsMonth .ogl_button:not(.material-icons){text-transform:uppercase}.ogl_dateBar{user-select:none;background:#181d26;-webkit-border-radius:5px;border-radius:5px;margin:20px 0;padding:4px;display:flex}.ogl_dateBar .ogl_item{box-sizing:border-box;cursor:ew-resize;flex:1;grid-template-rows:50px 16px;justify-content:center;align-items:end;padding:12px 2px 5px;display:grid;position:relative}.ogl_dateBar .ogl_item:after{content:attr(data-day);opacity:.3;pointer-events:none;text-align:center;display:block}.ogl_dateBar .ogl_item.ogl_active:after{opacity:1}.ogl_dateBar .ogl_item.ogl_today{text-decoration:underline}.ogl_dateBar .ogl_item>div{cursor:pointer;pointer-events:none;-webkit-border-radius:4px;border-radius:4px;width:20px;height:100%;font-size:10px;font-weight:700}.ogl_dateBar .ogl_selected{border-bottom:2px solid var(--ogl);border-top:2px solid var(--ogl);background:#524728;padding-top:10px;padding-bottom:3px}.ogl_dateBar .ogl_selected:not(.ogl_selected+.ogl_selected){border-left:2px solid var(--ogl);-webkit-border-top-left-radius:5px;border-top-left-radius:5px;-webkit-border-bottom-left-radius:5px;border-bottom-left-radius:5px;padding-left:0}.ogl_dateBar .ogl_selected:has(+:not(.ogl_selected)){border-right:2px solid var(--ogl);-webkit-border-top-right-radius:5px;border-top-right-radius:5px;-webkit-border-bottom-right-radius:5px;border-bottom-right-radius:5px;padding-right:0}.ogl_dateBar .ogl_item.ogl_selected:last-child{border-right:2px solid var(--ogl);-webkit-border-top-right-radius:5px;border-top-right-radius:5px;-webkit-border-bottom-right-radius:5px;border-bottom-right-radius:5px;padding-right:0}.ogl_dateBar>.ogl_item:hover{background:#524728}.ogl_popup.ogl_active .ogl_dateBar .ogl_active{pointer-events:all;color:#fff!important}.ogl_statsDetails{grid-gap:20px;grid-template-columns:430px 430px;align-items:end;display:grid}.ogl_statsDetails h3{color:var(--ogl);position:relative}.ogl_pie{background:var(--secondary);grid-gap:20px;-webkit-border-radius:5px;border-radius:5px;justify-content:center;align-items:center;height:182px;padding:0 20px;display:flex;position:relative}.ogl_pie:before{content:attr(data-pie);color:#fff;pointer-events:none;text-align:center;text-shadow:1px 1px 5px #000;white-space:pre;z-index:3;justify-content:center;align-items:center;width:200px;height:100%;font-size:12px;line-height:18px;display:grid;position:absolute;top:0;left:0}.ogl_noExpe{grid-gap:10px;display:grid}.ogl_pie span.material-icons{color:#313e4e;margin:auto;font-size:100px!important}.ogl_pie canvas{width:160px;height:160px}.ogl_pie .ogl_pieLegendContainer{-webkit-border-radius:5px;border-radius:5px;align-items:center;width:210px;min-height:120px;display:grid}.ogl_pie .ogl_pieLegend{cursor:pointer;grid-gap:5px;white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:18px auto 54px 41px;align-items:center;display:grid}.ogl_pie .ogl_pieLegend.ogl_active{box-shadow:0 0 0 2px #fff}.ogl_pie .ogl_pieLegend:hover{box-shadow:0 0 0 2px #fff}.ogl_pie .ogl_pieLegend>*{color:#fff;text-overflow:ellipsis;overflow:hidden}.ogl_pie .ogl_pieLegend>span{justify-self:right}.ogl_pie .ogl_pieLegend i{opacity:.6;text-align:right;font-size:smaller;font-weight:400}.ogl_pie .ogl_pieLegend .ogl_suffix{display:inline}.ogl_shipTable{grid-gap:5px;grid-template-columns:repeat(3,1fr);height:100%;display:grid}.ogl_shipTable>.ogl_icon{background:var(--secondary);box-sizing:border-box;padding-right:10px}.ogl_shipTable>.ogl_icon:before{width:38px;height:26px;margin-right:auto}.ogl_sumTable{grid-gap:3px;grid-column:1/-1;margin-top:20px;display:grid}.ogl_sumTable>*{grid-gap:3px;text-align:center;grid-template-columns:repeat(8,1fr);align-items:center;line-height:26px;display:grid}.ogl_sumTable>:first-child{font-size:20px!important}.ogl_sumTable>*>:not(.ogl_icon){background:var(--secondary);-webkit-border-radius:3px;border-radius:3px}.ogl_sumTable>*>:not(.ogl_icon):first-child{text-transform:capitalize}.ogl_sumTable .ogl_icon:before{margin:auto}.ogl_statsSettingsIcons{grid-gap:12px;background:#181d26;-webkit-border-radius:3px;border-radius:3px;margin-left:auto;padding:5px 26px 5px 8px;display:flex;position:absolute;top:-8px;right:0}.ogl_statsSettingsIcons>*{grid-gap:3px;justify-content:center;align-items:center;display:flex;position:relative}.ogl_statsSettingsIcons span{font-size:10px;position:absolute;top:9px;left:12px}.ogl_statsSettingsIcons .material-icons{color:#566279;position:relative;font-size:18px!important}.ogl_statsSettingsIcons .ogl_bool:after{color:#22bda2;content:"\\f103";text-shadow:-2px -1px 1px #000;font-size:12px;font-weight:700;display:block;position:absolute;top:48%;left:54%}.ogl_statsSettingsIcons .ogl_bool.ogl_active:after{color:red;content:"\\f13e"}.ogl_recap{background:var(--tertiary);cursor:pointer;user-select:none;z-index:11;-webkit-border-radius:3px;border-radius:3px;margin-top:3px;padding:10px 6px;position:relative;box-shadow:0 0 20px -5px #000,0 0 0 1px #17191c}.ogl_recap:hover{box-shadow:0 0 0 2px var(--ogl)}.ogl_recap>div{font-size:11px;font-weight:700}.ogl_recap .ogl_icon{text-align:right;background:0 0;grid-template-columns:28px auto 65px;display:grid}.ogl_recap .ogl_icon>:last-child{letter-spacing:-.03em;opacity:.5;font-size:10px}.ogl_recap .ogl_icon:before{vertical-align:bottom;height:14px}.ogl_shortCutWrapper{box-sizing:border-box;pointer-events:none;text-transform:uppercase;z-index:10;flex-direction:column;justify-content:center;width:100vw;height:calc(100dvh - 25px);display:flex;position:fixed;top:0;left:0}.ogl_shortCutWrapper>div:first-child{flex:1}.ogl_shortcuts{grid-gap:7px;flex-wrap:wrap;justify-content:center;display:flex}#planetbarcomponent #rechts .ogl_shortcuts{grid-gap:6px;justify-content:center;width:206px;margin-top:8px;transform:translate(-8px)}#planetbarcomponent #rechts .ogl_shortcuts .ogl_separator{display:none}.ogl_shortcuts *{z-index:1}.ogl_shortcuts [data-key]{grid-gap:2px;pointer-events:all;text-transform:uppercase;white-space:nowrap;justify-content:space-evenly;align-items:center;width:40px;font-size:11px;line-height:26px;display:inline-flex;position:relative;overflow:hidden;box-shadow:0 0 5px rgba(0,0,0,.6)}#planetbarcomponent #rechts .ogl_shortcuts [data-key]{width:33px}.ogl_shortcuts [data-key-id]:after{order:-1;font-family:Material Icons;font-size:16px!important}.ogl_shortcuts [data-key-id=menu]:after{content:"\\f10a"}.ogl_shortcuts [data-key-id=showMenuResources]:after{content:"\\f10f"}.ogl_shortcuts [data-key-id=previousPlanet]:after{content:"\\f14d"}.ogl_shortcuts [data-key-id=nextPlanet]:after{content:"\\f14c"}.ogl_shortcuts [data-key-id=expeditionSC]:after{color:var(--mission15);content:"\\f115"}.ogl_shortcuts [data-key-id=expeditionLC]:after{color:var(--mission15);content:"\\f115"}.ogl_shortcuts [data-key-id=expeditionPF]:after{color:var(--mission15);content:"\\f115"}.ogl_shortcuts [data-key-id=fleetRepeat]:after{content:"\\f14e"}.ogl_shortcuts [data-key-id=fleetSelectAll]:after{color:#ffab43;content:"\\f133"}.ogl_shortcuts [data-key-id=fleetReverseAll]:after{content:"\\f14f"}.ogl_shortcuts [data-key-id=backFirstFleet]:after{content:"\\f158"}.ogl_shortcuts [data-key-id=backLastFleet]:after{content:"\\f158"}.ogl_shortcuts [data-key-id=galaxyUp]:after{color:#30ba44;content:"\\f157"}.ogl_shortcuts [data-key-id=galaxyDown]:after{color:#30ba44;content:"\\f154"}.ogl_shortcuts [data-key-id=galaxyLeft]:after{color:#30ba44;content:"\\f155"}.ogl_shortcuts [data-key-id=galaxyRight]:after{color:#30ba44;content:"\\f156"}.ogl_shortcuts [data-key-id=galaxyReload]:after{content:"\\f151"}.ogl_shortcuts [data-key-id=discovery]:after{color:var(--lifeform);content:"\\f12c"}.ogl_shortcuts [data-key-id=galaxySpySystem]:after{color:var(--mission6);content:"\\f153"}.ogl_shortcuts [data-key-id=nextPinnedPosition]:after{content:"\\f120"}.ogl_shortcuts [data-key-id=fleetQuickCollect]:after{content:"\\f128"}.ogl_shortcuts .ogl_separator,fieldset .ogl_separator,.ogl_statsMonth .ogl_separator,.ogl_expeRecap .ogl_separator{background:#2e3840;-webkit-border-radius:50%;border-radius:50%;align-self:center;width:1px;height:1px;padding:2px}.ogl_shorcuts .ogl_button{box-shadow:0 1px 3px #000,0 1px 1px #405064}#technologydetails .build-it_wrap{transform-origin:100% 100%;transform:scale(.75)}#technologydetails .premium_info{font-size:14px}#technologydetails .information>ul{grid-gap:3px!important;flex-flow:row!important;width:auto!important;display:flex!important;position:absolute!important;top:auto!important;bottom:8px!important;left:1px!important}#technologydetails .information>ul li{background:var(--secondary);-webkit-border-radius:3px;border-radius:3px;padding:5px;margin-bottom:0!important}#technologydetails .build_duration,#technologydetails .additional_energy_consumption,#technologydetails .energy_production,#technologydetails .possible_build_start,#technologydetails .required_population,#technologydetails .research_laboratory_levels_sum{align-items:center;display:flex}#technologydetails .build_duration strong,#technologydetails .additional_energy_consumption strong,#technologydetails .energy_production strong,#technologydetails .possible_build_start strong,#technologydetails .required_population strong,#technologydetails .research_laboratory_levels_sum strong{font-size:0;display:inline-flex}#technologydetails .build_duration strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .additional_energy_consumption strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .energy_production strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .possible_build_start strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .required_population strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .research_laboratory_levels_sum strong:before{margin-right:3px;font-family:Material Icons;font-size:16px;display:block}#technologydetails .build_duration strong:before{color:var(--time);content:"\\f12d"}#technologydetails .possible_build_start strong:before{color:#ccc;content:"\\f152"}#technologydetails .additional_energy_consumption strong:before{color:var(--energy);content:"\\f102"}#technologydetails .energy_production strong:before{color:var(--energy);content:"\\f102"}#technologydetails .required_population strong:before{color:var(--lifeform);content:"\\f12c"}#technologydetails .research_laboratory_levels_sum strong:before{color:#21d19f;content:"\\f143"}#technologydetails .energy_production .bonus{color:#fff}#technologydetails .build_amount{top:35px}#technologydetails .build_amount label{display:none}#technologydetails .build_amount .maximum{background:0 0!important;min-width:0!important;margin:0 0 0 5px!important;padding:0!important}#technologydetails .build_amount .maximum:before{display:none!important}#technologydetails_wrapper.ogl_active{display:block!important}#technologydetails_wrapper.ogl_active #technologydetails_content{position:initial!important;display:block!important}#technologydetails_content{background:#0d1014!important}#technologydetails>.description{background:var(--primary)}#technologydetails .costs{top:33px!important;left:5px!important}#technologydetails .costs .ipiHintable{display:none!important}#technologydetails .costs .ogl_costsWrapper{grid-gap:3px;font-weight:700;display:grid}#technologydetails .costs .ogl_costsWrapper div:first-child .material-icons{color:inherit!important}#technologydetails .costs .ogl_costsWrapper .ogl_icon{grid-gap:8px;text-align:center;grid-template-columns:28px 70px 70px 70px;align-items:center;padding:0;display:grid!important}#technologydetails .costs .ogl_costsWrapper .ogl_icon:before{margin:0}#technologydetails .costs .ogl_costsWrapper .ogl_icon>div{background:var(--secondary);color:inherit;-webkit-border-radius:3px;border-radius:3px;line-height:18px!important}#technologydetails .resource.icon{flex:1 1 0;white-space:nowrap!important;-webkit-border-radius:5px!important;border-radius:5px!important;width:auto!important;height:auto!important;margin:0!important;padding:2px!important;font-size:12px!important}#technologydetails .resource.icon .ogl_text,#technologydetails .resource.icon .ogl_danger{font-size:10px}#technologydetails .ogl_actions{grid-gap:5px;grid-template-columns:repeat(4,1fr);padding:5px;line-height:28px;display:grid}#technologydetails .ogl_actions .ogl_button{font-size:18px!important}#technologydetails .ogl_actions .ogl_button.ogl_active{box-shadow:0 0 0 2px var(--amber);color:var(--amber)!important}#technologydetails .information .material-icons{color:#fff;vertical-align:bottom;font-size:16px!important}#technologydetails .information .costs>p{display:none}#technologydetails .information b{font-size:16px}.tippy-box .ogl_settingsTooltip ul{list-style:inside square}.tippy-box .ogl_settingsTooltip b,.tippy-box .ogl_readableTooltip b{color:var(--ogl);font-weight:700}.tippy-box .ogl_fleetDetail,.ogl_ptreContent .ogl_fleetDetail{grid-gap:4px 10px;grid-template-columns:repeat(2,1fr);font-size:11px;display:grid!important}.ogl_ptreContent .ogl_fleetDetail{grid-template-columns:repeat(3,1fr);padding:15px 0}.ogl_fleetDetail>div{background:var(--secondary);text-align:right;white-space:nowrap;-webkit-border-radius:3px;border-radius:3px;min-width:70px;line-height:20px;padding:0 5px 0 0!important}.ogl_fleetDetail .ogl_metal,.ogl_fleetDetail .ogl_crystal,.ogl_fleetDetail .ogl_deut,.ogl_fleetDetail .ogl_food{grid-column:1/-1}.ogl_fleetDetail .ogl_icon{color:#7c95ab;grid-gap:10px;font-weight:700}.ogl_fleetDetail .ogl_icon:before{margin-right:auto}.ogl_fleetDetail .ogl_button .ogl_icon:before{float:left}.ogl_fleetDetail .ogl_button{color:#fff;text-align:center;user-select:none;line-height:22px}.ogl_fullgrid{grid-column:1/-1}.tippy-box .ogl_fleetDetail .ogl_fullgrid{grid-gap:7px;grid-template-columns:repeat(2,1fr);display:grid}.tippy-box .ogl_fleetDetail .ogl_button span{pointer-events:none}.tippy-box .ogl_fleetDetail .ogl_button{grid-gap:3px;border:1px solid #17191c;grid-template-columns:16px auto;justify-content:center;align-items:center;padding:2px 12px;display:flex;font-size:12px!important}.tippy-box .ogl_fleetDetail .ogl_button .material-icons{font-size:16px!important}#fleetboxmission .content{min-height:0!important}#fleet2 #missionNameWrapper,#fleet2 ul#missions span.textlabel{display:none!important}.ogl_todoList{grid-gap:30px;grid-template-columns:auto auto;align-items:center;display:grid}.ogl_todoList .ogl_tech{background:#0b0f12;border-bottom:1px solid #1c2630;-webkit-border-radius:3px;border-radius:3px;margin-bottom:10px;padding:7px;display:grid}.ogl_todoList h2{grid-column:1/-1}.ogl_todoList h3{color:#5d6f81;cursor:pointer;text-align:left;text-transform:capitalize;-webkit-border-radius:3px;border-radius:3px;align-items:center;font-size:12px;line-height:18px;display:flex;position:relative;overflow:hidden}.ogl_todoList h3:after{content:"\\f105";margin-left:auto;font-family:Material Icons}.ogl_todoList h3:hover{color:#fff}.ogl_todoList h3:not(:first-child){margin-top:20px}.ogl_todoList h3 b{color:var(--ogl)}.ogl_todoList hr{background:#1e252e;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_todoList .ogl_line{grid-gap:8px;grid-template-columns:70px 114px 114px 114px 50px auto auto;transition:max-height .3s cubic-bezier(0,1,0,1);display:grid}.ogl_todoList div>.ogl_line:not(:first-child){max-height:0;overflow:hidden}.ogl_todoList .ogl_tech.ogl_active .ogl_line{max-height:28px;transition:max-height .1s ease-in-out}.ogl_todoList footer{border-top:2px solid #181f24;margin-top:3px}.ogl_todoList .ogl_line>*{background:var(--secondary);color:#849ab9;text-align:right;-webkit-border-radius:3px;border-radius:3px;align-items:center;margin-top:3px;padding-right:7px;display:flex}.ogl_todoList .ogl_line>:first-child{justify-content:center;padding-right:0;line-height:24px}.ogl_todoList .ogl_line .material-icons,.ogl_todoList .ogl_actions .material-icons{font-size:20px!important}.ogl_todoList .ogl_line .material-icons:hover{color:var(--ogl)!important}.ogl_todoList .ogl_line label{text-align:left}.ogl_todoList .ogl_line label:after{content:attr(data-order)}.ogl_todoList .ogl_line .ogl_icon:before{float:left}.ogl_todoList .ogl_line .ogl_textCenter{padding:0}.ogl_todoList .ogl_actions{grid-gap:7px;align-self:baseline;display:grid;position:sticky;top:0}.ogl_todoList .ogl_button{grid-gap:5px;align-items:center;padding:0 10px;display:flex}.ogl_todoList .ogl_button .material-icons{margin-left:auto}.ogl_removeTodo{color:#ff4f4f!important}.ogl_blockRecap>:last-child{color:#ff4f4f!important}.ogl_todoList .ogl_line button:hover{box-shadow:inset 0 0 0 2px var(--ogl);cursor:pointer}.originFleet *{color:inherit!important}.ogl_playerData .ogl_actions{grid-gap:2px;margin-bottom:10px;display:flex}.ogl_playerData .ogl_actions .ogl_button{border:1px solid #17191c;-webkit-border-radius:5px;border-radius:5px;width:100%;font-size:16px!important}.ogl_playerData .ogl_grid{grid-gap:12px;grid-template-columns:repeat(2,1fr);display:grid}.ogl_playerData .ogl_tagSelector{grid-column:1/-1}.ogl_playerData .ogl_leftSide{background:#101418;-webkit-border-radius:5px;border-radius:5px;padding:7px;font-size:12px}.ogl_playerData h1{background:var(--primary);text-align:center;width:fit-content;border:2px solid #202834;-webkit-border-radius:50px;border-radius:50px;width:-moz-fit-content;margin:0 auto 14px;padding:3px 12px;font-size:14px}.ogl_playerData h1:before{content:"";background:red;height:2px}.ogl_playerData h1 a{font-size:12px;text-decoration:none}.ogl_playerData h1 a:hover{color:var(--ogl)}.ogl_score{grid-gap:3px;display:grid}.ogl_score .material-icons{font-size:16px!important;line-height:20px!important}.ogl_score .ogl_line{background:var(--secondary);grid-gap:3px;-webkit-border-radius:5px;border-radius:5px;grid-template-columns:20px auto;padding:1px 5px;display:grid}.ogl_score .ogl_line div{text-align:right;line-height:20px}.ogl_score .ogl_line:first-child{color:#f9c846}.ogl_score .ogl_line:nth-child(2){color:#6dd0ff}.ogl_score .ogl_line:nth-child(3){color:#21d19f}.ogl_score .ogl_line:nth-child(4){color:var(--lifeform)}.ogl_score .ogl_line:nth-child(5){color:#ff4646}.ogl_score .ogl_line:nth-child(6){color:#f96e46}.ogl_score .ogl_line:nth-child(7){color:#bfbfbf}.ogl_pinDetail .ogl_score .ogl_line:nth-child(7){color:#8b84ff;grid-column:1/-1}.ogl_playerData .ogl_planetStalk{grid-gap:3px;background:#101418;-webkit-border-radius:5px;border-radius:5px;flex-direction:column;padding:7px;display:flex}.ogl_playerData .ogl_planetStalk>div{grid-gap:3px;grid-template-columns:24px auto 22px 22px 22px;font-size:12px;display:grid;position:relative}.ogl_playerData .ogl_planetStalk>div:last-child{border:none}.ogl_playerData .ogl_planetStalk>div>*{background:var(--secondary);-webkit-border-radius:3px;border-radius:3px;justify-content:center;align-items:center;padding:0 5px;line-height:22px;display:flex}.ogl_playerData .ogl_tagPicker{pointer-events:none!important;background:0 0!important}.ogl_playerData .ogl_tagPicker:before{content:"fiber_manual_record"!important}.ogl_playerData .ogl_planetStalk [data-galaxy]{justify-content:left}.ogl_home [data-galaxy]:before{color:#fff;content:"\\f109";margin-right:5px;font-family:Material Icons;text-decoration:none;display:inline-block}.ogl_playerData .ogl_planetStalk .ogl_spyIcon{color:#687a89;font-size:15px!important}.ogl_playerData .ogl_planetStalk .ogl_spyIcon:hover{color:#fff}#jumpgate .ship_input_row{position:relative}#jumpgate .ogl_keepRecap{color:#f45757;background:#4c1b1b;-webkit-border-radius:4px;border-radius:4px;padding:2px 4px;font-size:10px;position:absolute;bottom:0;right:0}#jumpgate .ship_input_row input{text-align:left}.eventFleet .tooltip{color:inherit}.galaxyTable .ogl_flagPicker{margin-left:3px}.ogl_flagPicker,.ogl_flagSelector{cursor:pointer;min-height:19px;font-size:19px!important}.ogl_flagSelector>*{justify-content:center;align-items:center;display:grid}.ogl_tooltip .ogl_flagSelector>*{height:100%;min-height:19px}.ogl_flagPicker:before{color:#4e5c68;content:"keep"}.ogl_flagSelector [data-flag=none]:before{color:#4e5c68;content:"keep"}.ogl_flagPicker[data-flag=friend]:before{color:#ff78cf;content:"handshake"}.ogl_flagSelector [data-flag=friend]:before{color:#ff78cf;content:"handshake"}.ogl_flagPicker[data-flag=danger]:before{color:#ff4343;content:"warning"}.ogl_flagSelector [data-flag=danger]:before{color:#ff4343;content:"warning"}.ogl_flagPicker[data-flag=skull]:before{color:#e9e9e9;content:"skull"}.ogl_flagSelector [data-flag=skull]:before{color:#e9e9e9;content:"skull"}.ogl_flagPicker[data-flag=rush]:before{color:#6cddff;content:"electric_bolt"}.ogl_flagSelector [data-flag=rush]:before{color:#6cddff;content:"electric_bolt"}.ogl_flagPicker[data-flag=fridge]:before{color:#667eff;content:"kitchen"}.ogl_flagSelector [data-flag=fridge]:before{color:#667eff;content:"kitchen"}.ogl_flagPicker[data-flag=star]:before{color:#ffd745;content:"star"}.ogl_flagSelector [data-flag=star]:before{color:#ffd745;content:"star"}.ogl_flagPicker[data-flag=trade]:before{color:#32db9d;content:"local_gas_station"}.ogl_flagSelector [data-flag=trade]:before{color:#32db9d;content:"local_gas_station"}.ogl_flagPicker[data-flag=money]:before{color:#ab7b65;content:"euro_symbol"}.ogl_flagSelector [data-flag=money]:before{color:#ab7b65;content:"euro_symbol"}.ogl_flagPicker[data-flag=ptre]:before{color:#ff942c;content:"ptre"}.ogl_flagSelector [data-flag=ptre]:before{color:#ff942c;content:"ptre"}.ogl_flagPicker[data-flag=recent]:before{color:#41576c;content:"schedule"}.ogl_flagSelector [data-flag=recent]:before{color:#41576c;content:"schedule"}.ogl_flagPicker:hover{filter:brightness(1.3)}.ogl_flagSelector [data-flag]:hover{filter:brightness(1.3)}.ogl_tagPicker:hover{filter:brightness(1.3)}.ogl_tagSelector [data-tag]:hover{filter:brightness(1.3)}.ogl_flagSelector [data-flag]:hover:after{content:"";border-top:6px solid #fff;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;top:-8px;left:50%;transform:translate(-50%)}.ogl_tagSelector [data-tag]:hover:after{content:"";border-top:6px solid #fff;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;top:-8px;left:50%;transform:translate(-50%)}.tippy-content .ogl_flagSelector,.tippy-content .ogl_tagSelector{grid-gap:4px 10px;grid-auto-flow:column;justify-content:center;align-items:center;display:flex!important}.ogl_tooltip>div.ogl_flagSelector:not(.ogl_tooltipTriangle):not(.ogl_close){grid-gap:4px 10px;grid-auto-flow:column;justify-content:center;align-items:center;display:flex!important}.ogl_tooltip>div.ogl_tagSelector:not(.ogl_tooltipTriangle):not(.ogl_close){grid-gap:4px 10px;grid-auto-flow:column;justify-content:center;align-items:center;display:flex!important}.ogl_tagPicker,.ogl_tagSelector{cursor:pointer;user-select:none;font-size:19px!important}.ogl_tagPicker:before{content:"stroke_full"}.ogl_tagSelector [data-tag]:before{content:"stroke_full"}.ogl_tagPicker:before{color:#4e5c68}.ogl_tagSelector [data-tag=none]:before{color:#4e5c68}.ogl_tagPicker[data-tag=red]:before{color:#eb3b5a}.ogl_tagSelector [data-tag=red]:before{color:#eb3b5a}.ogl_tagPicker[data-tag=orange]:before{color:#fa8231}.ogl_tagSelector [data-tag=orange]:before{color:#fa8231}.ogl_tagPicker[data-tag=yellow]:before{color:#f7b731}.ogl_tagSelector [data-tag=yellow]:before{color:#f7b731}.ogl_tagPicker[data-tag=lime]:before{color:#7bbf20}.ogl_tagSelector [data-tag=lime]:before{color:#7bbf20}.ogl_tagPicker[data-tag=green]:before{color:#20bf6b}.ogl_tagSelector [data-tag=green]:before{color:#20bf6b}.ogl_tagPicker[data-tag=blue]:before{color:#5bbde3}.ogl_tagSelector [data-tag=blue]:before{color:#5bbde3}.ogl_tagPicker[data-tag=dblue]:before{color:#3867d6}.ogl_tagSelector [data-tag=dblue]:before{color:#3867d6}.ogl_tagPicker[data-tag=violet]:before{color:#8854d0}.ogl_tagSelector [data-tag=violet]:before{color:#8854d0}.ogl_tagPicker[data-tag=magenta]:before{color:#f95692}.ogl_tagSelector [data-tag=magenta]:before{color:#f95692}.ogl_tagPicker[data-tag=pink]:before{color:#fda7df}.ogl_tagSelector [data-tag=pink]:before{color:#fda7df}.ogl_tagPicker[data-tag=brown]:before{color:#996c5c}.ogl_tagSelector [data-tag=brown]:before{color:#996c5c}.ogl_tagPicker[data-tag=gray]:before{color:#75a1b7}.ogl_tagSelector [data-tag=gray]:before{color:#75a1b7}[data-tag].ogl_off{opacity:.2}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=red]){box-shadow:inset 0 0 100px rgba(255,0,0,.2)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=orange]){box-shadow:inset 0 0 100px rgba(235,108,59,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=yellow]){box-shadow:inset 0 0 100px rgba(235,181,59,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=lime]){box-shadow:inset 0 0 100px rgba(167,235,59,.2)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=green]){box-shadow:inset 0 0 100px rgba(59,235,89,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=blue]){box-shadow:inset 0 0 100px rgba(59,162,235,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=dblue]){box-shadow:inset 0 0 100px rgba(59,81,235,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=violet]){box-shadow:inset 0 0 100px rgba(110,59,235,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=magenta]){box-shadow:inset 0 0 100px rgba(235,59,165,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=pink]){box-shadow:inset 0 0 100px rgba(255,124,179,.3)}#galaxyContent .ctContentRow .galaxyCell:has([data-tag=brown]){box-shadow:inset 0 0 100px rgba(149,111,89,.3)}.galaxyRow:has([data-tag=gray]){opacity:.2}.galaxyTable .ogl_tagPicker,.ogl_spytable .ogl_tagPicker{margin-left:auto}.galaxyTable .phalanxlink{margin-left:auto!important}.galaxyTable .phalanxlink+.ogl_tagPicker{margin-left:1px}.ogl_list{grid-gap:3px;background:#0e1116;padding:10px;display:grid}.ogl_list .ogl_emptyList{padding:10px}.ogl_list>div{grid-gap:4px;-webkit-border-radius:3px;border-radius:3px;align-items:center;display:grid;position:relative}.ogl_list>div>:not(.ogl_button){background:var(--secondary);-webkit-border-radius:3px;border-radius:3px;justify-content:center;align-items:center;padding:0 5px;display:flex;line-height:24px!important}.ogl_list>div>.ogl_flagPicker{padding:0}.ogl_pinned .ogl_list>div{grid-template-columns:auto 70px 30px 30px}.ogl_pinned .ogl_list>div>:first-child{justify-content:left}.ogl_pinned .ogl_list .ogl_grid{grid-template-columns:repeat(2,1fr);display:grid}.ogl_pinned .ogl_list .material-icons{cursor:pointer;user-select:none;text-align:right;height:24px!important;font-size:17px!important}.ogl_pinned .ogl_list .material-icons:hover{filter:brightness(1.3)}.ogl_pinned .ogl_list .material-icons:last-child{color:#915454}.ogl_pinned .ogl_detail{cursor:pointer}.ogl_pinned .ogl_detail:hover{color:#fff}.ogl_pinned .ogl_tabs{text-align:center;grid-template-columns:repeat(9,1fr);justify-content:space-between;display:flex}.ogl_pinned .ogl_tabs>[data-flag]{justify-content:center;align-items:center;padding:5px 7px 7px;display:grid}.ogl_pinned .ogl_tabs .ogl_active{background:#0e1116;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.ogl_pinned span:hover{cursor:pointer;text-decoration:underline}.ogl_expeditionFiller{grid-template-columns:repeat(8,1fr);display:grid}.ogl_expeditionFiller h2{grid-column:1/-1}.ogl_expeditionFiller .ogl_icon:before{width:38px;height:38px}.ogl_expeditionFiller .ogl_icon:hover:before{cursor:pointer;box-shadow:0 0 0 2px var(--ogl)}.ogl_expeditionFiller .ogl_icon.ogl_active:before{box-shadow:0 0 0 2px #fff}.ogl_wrapperloading{background:rgba(0,0,0,.7);justify-content:center;align-items:center;width:100%;height:100%;display:flex}.ogl_loading{background:conic-gradient(rgba(255,255,255,0),var(--ogl));-webkit-border-radius:50%;border-radius:50%;width:25px;height:25px;animation:.75s linear infinite spinAlt;mask:radial-gradient(transparent 40%,#fff 43%,#fff 0)}@keyframes spinAlt{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ogl_pinDetail h2{grid-gap:5px;display:flex}.ogl_pinDetail h2 .ogl_flagPicker{margin:0}.ogl_pinDetail .ogl_actions{grid-gap:3px;margin-bottom:20px;display:flex}.ogl_pinDetail .ogl_actions .ogl_button{flex:1;justify-content:center;align-items:center;display:grid;font-size:16px!important}.ogl_pinDetail .ogl_score{grid-template-columns:repeat(2,1fr);margin-bottom:20px}.ogl_pinDetail .ogl_score>div{padding:4px 5px}.ogl_pinDetail .ogl_list>div{grid-template-columns:20px auto 60px 38px 38px 67px}.ogl_pinDetail .ogl_list [data-galaxy]{justify-content:left}.ogl_pinDetail .ogl_list .ogl_spyIcon{color:#687a89;justify-content:space-between;padding:0 3px;font-size:16px!important}.ogl_pinDetail .ogl_list .ogl_spyIcon:hover{color:#fff}.ogl_spyIcon{align-items:center;display:flex;cursor:pointer!important}.ogl_spyIcon span{margin-left:3px;font-family:Verdana,Arial,SunSans-Regular,sans-serif;font-size:11px}.ogl_spyIcon.ogl_attacked:before{content:"send";color:var(--mission1);pointer-events:none;text-shadow:1px 2px 3px #000;font-family:Material Icons;display:block;position:absolute;bottom:-6px;left:-3px;font-size:18px!important}[data-debris-coords].ogl_attacked:before{content:"send";color:var(--mission1);pointer-events:none;text-shadow:1px 2px 3px #000;font-family:Material Icons;display:block;position:absolute;bottom:-6px;left:-3px;font-size:18px!important}[data-debris-coords]{position:relative}[data-debris-coords]:before{color:var(--mission8)!important}.ogl_pinDetail date{grid-gap:5px;font-size:10px;display:grid}.ogl_pinDetail date span:first-child{color:var(--date)}.ogl_pinDetail date span:nth-child(2){color:var(--time)}.ogl_nextQuickTarget{color:#687a89;font-size:16px!important}.ogl_nextQuickTarget.ogl_active{color:var(--red)}.ogl_tagged .ogl_grid{grid-gap:5px;justify-content:end;align-items:center;display:flex}.ogl_tagged .ogl_grid label{align-items:center;display:flex}.ogl_tagged .ogl_list>div{grid-template-columns:30px auto 30px 30px 30px 30px}.ogl_tagged .ogl_list>div>div:first-child{text-align:center}.ogl_tagged .ogl_list .ogl_spyIcon{color:#687a89;font-size:16px!important}.ogl_tagged .ogl_list .ogl_spyIcon:hover{color:#fff}.ogl_tagged .ogl_tabs,.ogl_playerData .ogl_tagSelector{grid-gap:12px 6px;text-align:center;margin-bottom:8px;display:flex}.ogl_tagged .ogl_tabs>*{flex:1}.ogl_playerData .ogl_tagSelector>*{flex:1}.ogl_tagged .ogl_actions{grid-gap:0 4px;grid-template-columns:repeat(15,1fr);align-items:center;display:grid}.ogl_tagged .ogl_actions input{box-shadow:none!important;color:#5d738d!important;background:#121518!important;border:none!important;border-top:1px solid #080b10!important;border-bottom:1px solid #212830!important;-webkit-border-radius:3px!important;border-radius:3px!important;font-weight:700!important}.ogl_tagged .ogl_actions label{cursor:pointer;background:linear-gradient(#405064,#2d3743 2px,#181e25);-webkit-border-radius:50px;border-radius:50px;justify-content:center;align-items:center;display:flex}.ogl_tagged .ogl_actions .material-icons{color:#7d8caa;cursor:default;text-align:center;user-select:none;font-size:16px!important}.ogl_tagged .ogl_actions input,.ogl_tagged .ogl_actions .ogl_button,.ogl_tagged .ogl_actions label{text-align:center;user-select:none;grid-column:span 2;align-self:flex-start;width:auto;line-height:24px!important}.ogl_tagged .ogl_actions .ogl_button,.ogl_tagged .ogl_list .ogl_button{cursor:pointer;text-align:center;user-select:none;grid-template-columns:auto;padding:0 4px;line-height:26px;display:inline-block}.ogl_tagged .ogl_actions .ogl_button:hover{color:#fff}.ogl_tagged .ogl_list .ogl_button:hover{color:#fff}.tippy-content:has(.ogl_planetTooltip){background:url(https://gf2.geo.gfsrv.net/cdn4e/d07c90d96bbc823d6d53953a94aacb.jpg) 50%/cover!important;padding:0!important}.ogl_planetTooltip{color:#fff;background:linear-gradient(rgba(74,218,251,.33),rgba(11,68,102,.46) 30px,rgba(2,12,14,.86));-webkit-border-radius:7px;border-radius:7px;width:175px;padding:22px;position:relative}.ogl_planetTooltip>div:first-child{align-items:center;display:grid}.ogl_planetTooltip [class*=ogl_lifeform]{border:2px solid var(--lifeform);background:#000;-webkit-border-radius:50%;border-radius:50%;position:absolute;top:70px;left:65%;box-shadow:0 0 5px 2px #000}.ogl_planetTooltip [class*=ogl_lifeform]:before{-webkit-border-radius:50%;border-radius:50%}.ogl_planetTooltip h3{font-size:15px}.ogl_planetTooltip h3 span{font-size:11px;display:inline}.ogl_planetTooltip img{filter:drop-shadow(2px 4px 6px #000);width:125px;height:125px;margin:0 auto 7px;display:block}.ogl_planetTooltip a{display:block}.ogl_planetTooltip a:hover{color:#fff!important}.ogl_planetTooltip .ogl_linkDiv{border-top:2px solid #143a50;margin-top:7px;padding-top:7px}.ogl_planetTooltip .ogl_linkDiv a{color:#74b0c7}.ogl_planetTooltip h3{text-align:center}.ogl_planetTooltip .ogl_mineRecap{text-align:center;margin-top:5px;font-size:14px;font-weight:700}.ogl_planetTooltip .ogl_planetTooltipData{grid-gap:15px;justify-content:center;display:flex}.ogl_planetTooltip .ogl_planetTooltipData>*{grid-gap:4px;align-items:center;display:flex}.ogl_planetTooltip .ogl_planetTooltipData .material-icons{color:#74b0c7;font-size:14px!important}#empire #siteFooter .content,#siteFooter .content{width:1045px!important}.ogl_danger{color:#ff665b!important}.ogl_warning{color:var(--amber)!important}.ogl_caution{color:var(--yellow)!important}.ogl_ok{color:#77ddae!important}.ogl_ping{color:#aaa;align-items:center;font-size:10px;font-weight:700;display:flex;position:absolute;top:23px;right:0}.ogl_ping:before{content:"\\f173";margin-right:3px;font-family:Material Icons;font-size:12px;display:block}.secondcol>[class*=ogl_]{color:#fff;cursor:pointer;background:linear-gradient(#424e5e 50%,#222f3c 50%);justify-content:center;align-items:center;display:inline-flex;text-align:center!important;text-shadow:1px 1px #000!important;-webkit-border-radius:3px!important;border-radius:3px!important;width:32px!important;height:26px!important;font-size:20px!important;line-height:26px!important;text-decoration:none!important;transform:scale(1)!important}.secondcol>span>.material-icons{color:#fff;cursor:pointer;background:linear-gradient(#424e5e 50%,#222f3c 50%);justify-content:center;align-items:center;display:inline-flex;text-align:center!important;text-shadow:1px 1px #000!important;-webkit-border-radius:3px!important;border-radius:3px!important;width:32px!important;height:26px!important;font-size:20px!important;line-height:26px!important;text-decoration:none!important;transform:scale(1)!important}.secondcol>[class*=ogl_]:hover{filter:brightness(1.2);color:#ccc!important}.secondcol>span>.material-icons:hover{filter:brightness(1.2);color:#ccc!important}.secondcol .ogl_recordBtn{padding:0 3px 0 8px;width:auto!important;font-size:11px!important}.secondcol .ogl_recordBtn .material-icons{color:var(--red);font-size:16px!important}.secondcol #resetall.material-icons{background:linear-gradient(#812727 50%,#5c1515 50%)}.secondcol #sendall.material-icons{background:linear-gradient(#b76908 50%,#9b4a11 50%)}.ogl_tooltip>div.ogl_resourcesPreselection:not(.ogl_tooltipTriangle):not(.ogl_close){grid-gap:5px;display:grid!important}.ogl_tooltip>div.ogl_resourcesPreselection .ogl_icon{padding:0}.ogl_resourcesPreselection{grid-gap:5px;display:grid!important}.ogl_resourcesPreselection .ogl_icon{padding:0}.ogl_resourcesPreselection .ogl_icon:before{color:#ffc800;content:"chevron-double-right";text-align:center;text-shadow:1px 1px 2px #000;font-family:Material Icons;font-size:20px;line-height:18px}.ogl_resourcesPreselection hr{border:none;width:100%;height:2px}.ogl_resourcesPreselection .ogl_button{line-height:30px}[data-spy=prepare]{color:var(--amber)!important}[data-spy=done]{color:var(--teal)!important}[data-spy=fail]{color:var(--red)!important}[data-spy=recent]{color:var(--purple)!important}[data-spy]:not(.ogl_spyIcon){-webkit-border-radius:2px!important;border-radius:2px!important;box-shadow:0 0 0 2px!important}.expeditionDebrisSlotBox{align-items:center;box-shadow:none!important;box-sizing:border-box!important;border:none!important;flex-wrap:wrap!important;width:642px!important;padding:4px 16px!important;display:flex!important}.expeditionDebrisSlotBox.ogl_hidden,#expeditionDebrisSlotDebrisContainer{display:none!important}.expeditionDebrisSlotBox li{list-style:none}.expeditionDebrisSlotBox>div{grid-gap:20px;text-align:left;line-height:1.4;display:flex}.expeditionDebrisSlotBox a{color:var(--green1)}.expeditionDebrisSlotBox a:hover{text-decoration:underline}.ogl_expeditionRow{border-top:2px solid #1a2129;margin-top:5px;padding-top:5px;grid-gap:10px!important;width:100%!important}.ogl_expeditionRow.ogl_important{border:none;-webkit-border-radius:5px;border-radius:5px;padding:0}.ogl_expeditionRow>div:not(:last-child){display:flex}.ogl_expeditionRow *{white-space:nowrap}.ogl_expeditionText{line-height:24px}.ogl_expeditionDebris{grid-gap:10px;display:flex}.ogl_sideFleetTooltip:not(.ogl_tooltipTriangle):not(.ogl_close){grid-gap:2px;font-size:11px;max-width:800px!important;display:grid!important}.ogl_sideFleetIcon{grid-gap:5px;grid-template-columns:70px 28px 30px 70px 60px 20px 30px 70px 98px 98px 98px;justify-content:center;align-items:center;display:grid}.ogl_sideFleetIcon>:not(img){background:var(--secondary);-webkit-border-radius:3px;border-radius:3px}.ogl_sideFleetIcon>:not(img):not(.ogl_icon){text-align:center;padding:0 3px;line-height:24px}.ogl_sideFleetIcon .material-icons{color:#fff;font-size:14px!important;line-height:24px!important}.ogl_sideFleetIcon>span{color:#fff}.ogl_sideFleetIcon .ogl_icon[class*=ogl_mission]:before{width:18px;background-size:200px!important;margin:auto!important}.ogl_sideFleetIcon .ogl_icon.ogl_mission18:before{background-size:18px!important}[data-return-flight=true]>:not(.ogl_clockNotif){opacity:.5;background-color:rgba(0,0,0,.7)}#phalanxEventContent [data-return-flight=true]{filter:brightness(.6)}#phalanxEventContent [data-return-flight=true]>:not(.ogl_clockNotif){opacity:1;background:0 0}#movementcomponent .starStreak .route{color:#aaa;text-align:center}#movementcomponent .starStreak .route b{color:#fff;font-weight:400}.msg gradient-button .custom_btn{border:none!important}gradient-button img{pointer-events:none!important}.msg:has(.ogl_checked) message-footer-details{margin-right:48px}.ogl_messageButton{cursor:pointer;float:left;text-align:center;-webkit-border-radius:5px;border-radius:5px;width:28px;height:28px;font-weight:700;box-shadow:0 2px 3px 1px rgba(0,0,0,.55);color:#9ea5af!important;background:linear-gradient(160deg,#364d63 0%,#283948 33%,#141e26 66%,#121a21 100%)!important;font-size:20px!important;line-height:28px!important}.ogl_messageButton:hover{box-shadow:0 0 transparent;background:linear-gradient(160deg,#436b91 0%,#344c61 33%,#283a47 66%,#141a20 100%)!important}message-footer-actions gradient-button[sq30]{width:26px!important;height:26px!important}.ogl_messageButton.ogl_ignore.ogl_active{color:#c65757!important}.ogl_messageButton.ogl_ignore:before{content:"toggle_off";font-family:Material Icons;font-size:18px!important}.ogl_messageButton.ogl_ignore.ogl_active:before{content:"toggle_on"}.ogl_messageButton.ogl_ignore:hover:after{display:inline-block}.ogl_resourcesDetail{grid-gap:5px;grid-template-columns:repeat(4,1fr);max-width:800px;display:grid!important}.ogl_resourcesDetail .ogl_group{border-bottom:2px solid #28303c;justify-content:center;align-items:center;gap:5px;margin-bottom:8px;padding-bottom:8px;display:flex}.ogl_resourcesDetail>div:last-child{grid-column:1/-1}.ogl_resourcesDetail>div:not(.ogl_close){background:var(--secondary);text-align:center;-webkit-border-radius:5px;border-radius:5px;padding:10px 15px;line-height:15px;position:relative}.ogl_resourcesDetail .ogl_todoDays>.ogl_unit+span{color:var(--ogl);font-size:11px}.ogl_resourcesDetail .ogl_todoDays>.ogl_unit+span:before{color:#6b7597;content:"- "}.ogl_resourcesDetail h3,.ogl_resourcesDetail h4{color:#9ea4af;display:block}.ogl_resourcesDetail h3{font-size:18px!important}.ogl_resourcesDetail h4{font-size:14px!important}[data-api-code]{cursor:pointer}.reversal{overflow:unset!important}.reversal a[data-key-color]:before{color:transparent;content:"\\f12f";pointer-events:none;text-shadow:-1px 1px 2px rgba(0,0,0,.4);font-family:Material Icons;font-size:11px;line-height:12px;position:absolute;top:-3px;right:-4px}.reversal a:before{top:0;right:-6px}.ogl_button[data-key-color=orange]:after{color:#ff7806}.ogl_button[data-key-color=violet]:after{color:#fa59fd}.ogl_button[data-key-color=blue]:after{color:var(--mission15)}.ogl_button[data-key-color=cyan]:after{color:#7bffed}.reversal a[data-key-color=orange]:before{color:#ff7806}.reversal a[data-key-color=violet]:before{color:#fa59fd}[data-key-color=undefined]:before{display:none!important}.resourceIcon .ogl_reverse{color:#b1c2cb;text-shadow:1px 2px #000;z-index:10;position:absolute;top:3px;right:5px;font-size:14px!important}.resourceIcon .ogl_reverse:hover{opacity:1}.resourceIcon .ogl_reverse{top:1px;right:2px}.ogl_notification{opacity:0;pointer-events:none;transform-origin:100%;z-index:1000003;background:#191f26;min-width:275px;max-height:500px;padding:14px 14px 11px;font-weight:700;transition:transform .2s;position:fixed;bottom:5px;right:5px;overflow-x:hidden;overflow-y:auto;transform:scaleX(0);box-shadow:0 0 20px 10px rgba(0,0,0,.7)}.ogl_notification.ogl_active{opacity:1;pointer-events:all;transform:scaleX(1)}.ogl_notificationLine{grid-gap:7px;border-bottom:1px solid #2b3a42;max-width:380px;padding:8px 0;font-size:11px;line-height:15px;display:flex}.ogl_notificationLine:last-child{border:none}.ogl_notification>div>:last-child>hr:last-child{display:none}.ogl_notification progress{appearance:none;width:100%;height:3px;position:absolute;top:0;left:0}.ogl_notification progress::-webkit-progress-value{appearance:none;background:var(--ogl);transition:width .2s linear}.ogl_notification progress::-moz-progress-bar{appearance:none;background:var(--amber);transition:width .2s linear}.ogl_notification .ogl_ok,.ogl_notification .ogl_danger{vertical-align:middle;margin-left:4px;font-size:12px!important}.ogl_notification h2{text-align:center;font-size:14px}.ogl_notification .ogl_grid{grid-gap:5px;grid-template-columns:repeat(2,1fr);max-width:275px;display:grid}.ogl_notification .ogl_icon{background:#1f2730;-webkit-border-radius:3px;border-radius:3px;align-items:center;display:flex}.ogl_notification .ogl_icon:before{margin-right:auto}.ogl_notification .ogl_icon[class*=lifeform]:before{image-rendering:auto;background-position-y:77%;background-size:335px;width:28px;height:18px}.ogl_notification .ogl_icon .ogl_suffix{text-indent:0}.ogl_notification .ogl_notificationTimer{color:var(--date);opacity:.5;margin-right:5px;font-size:11px;display:inline-block}.ogl_empireJumpgate{text-align:center;width:100%;margin-top:3px;font-size:20px!important}#eventboxContent .eventFleet,#eventboxContent .allianceAttack{grid-gap:2px;white-space:nowrap;z-index:1;grid-template-columns:82px 62px 23px 70px 87px auto 19px 87px 70px 20px 21px 20px;align-items:center;display:grid;position:relative}#eventboxContent .eventFleet:hover{z-index:2}#eventboxContent .eventFleet>td{box-sizing:border-box;text-align:center;-webkit-border-radius:2px;border-radius:2px;justify-content:left;align-items:center;width:100%;height:calc(100% - 2px);padding:2px 4px;display:flex;overflow:hidden;box-shadow:0 0 0 2px #110e1c,inset 0 10px rgba(255,255,255,.03)}#eventboxContent .eventFleet td.arrivalTime{justify-content:center}#eventboxContent .eventFleet td.coordsOrigin{justify-content:center}#eventboxContent .eventFleet td.destCoords{justify-content:center}#eventboxContent .eventFleet>td:not(.icon_movement):not(.icon_movement_reserve){padding:2px}#eventboxContent .eventFleet>td:nth-child(3){background:0 0!important}#eventboxContent .eventFleet>td:nth-child(5){grid-area:1/4}#eventboxContent .eventFleet>td:nth-child(10) span{display:flex!important}#eventboxContent .eventFleet>td:nth-child(11) span{display:flex!important}#eventboxContent .eventFleet>td:nth-child(12) span{display:flex!important}#eventboxContent .eventFleet>td a{text-decoration:none!important}#eventboxContent .eventFleet>td a:hover{color:var(--ogl)!important}.eventFleet [data-output-time]{justify-self:flex-start}.icon_movement,.icon_movement_reserve{background-position:50%!important}.originFleet,.destFleet{grid-gap:2px;justify-content:center;align-items:center;display:flex}.originFleet .tooltip[data-title]:not(figure){grid-gap:1px;align-items:center;font-size:0;display:inline-flex!important}.destFleet .tooltip[data-title]:not(figure){grid-gap:1px;align-items:center;font-size:0;display:inline-flex!important}.originFleet .tooltip[data-title]:not(figure):after{content:attr(data-title);text-overflow:ellipsis;font-size:11px;overflow:hidden}.destFleet .tooltip[data-title]:not(figure):after{content:attr(data-title);text-overflow:ellipsis;font-size:11px;overflow:hidden}.originFleet figure,.destFleet figure{flex-shrink:0}#technologydetails .ogl_queueShip{display:flex;position:absolute;top:52px}#technologydetails .ogl_queueShip .ogl_button{-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;width:60px}#technologydetails .ogl_queueShip input{box-shadow:none;box-sizing:border-box;color:#5d738d;text-align:left;background:#121518;border:none;border-top:1px solid #080b10;border-bottom:1px solid #242a32;-webkit-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;width:45px;padding:0 4px}.fleetDetails{overflow:unset!important;background:linear-gradient(#1a1d24,#0e1014 26px)!important;border:none!important;-webkit-border-radius:0!important;border-radius:0!important;width:96%!important;margin:12px 0 0 6px!important;padding:5px!important;line-height:18px!important;display:inline-block!important;position:relative!important;box-shadow:0 0 20px -5px #000,0 0 0 1px #000!important}.fleetDetails.detailsOpened{height:auto!important}.fleetDetails .starStreak,.fleetDetails .nextMission,.fleetDetails .mission,.fleetDetails.detailsClosed .ogl_shipsBlock,.fleetDetails.detailsClosed .ogl_resourcesBlock,.fleetDetails.detailsClosed .fedAttack,.fleetDetails.detailsClosed .sendMail,.fleetDetails .fleetDetailButton,.fleetDetails .marker01,.fleetDetails .marker02{display:none!important}.fleetDetails hr{background:#1e252e;border:none;height:2px}.fleetDetails .openDetails{position:absolute!important;top:-2px!important;left:auto!important;right:0!important}.fleetDetails.detailsOpened .timer{height:auto!important}.ogl_resourcesBlock{box-sizing:border-box;grid-gap:5px;text-wrap:nowrap;grid-template-columns:repeat(8,1fr);width:100%;margin-top:5px;font-size:11px;display:grid}.ogl_resourcesBlock .ogl_icon{background:#191d26;justify-content:end;margin:0;padding:3px}.ogl_resourcesBlock .ogl_icon:before{margin:0 auto 0 0;display:block}.ogl_shipsBlock{box-sizing:border-box;color:#fff;grid-template-columns:repeat(3,1fr);display:grid}.ogl_backTimer{box-sizing:border-box;text-align:right;grid-area:1/-3/auto/-1;align-items:center;padding:5px 32px 5px 5px;font-size:0;box-shadow:0 0 0 1px #000;line-height:14px!important}.ogl_backTimer:before{font-size:11px}.ogl_backTimer:after{font-size:11px}.ogl_backTimer:hover{box-shadow:0 0 0 2px var(--ogl);color:transparent!important}.fleetDetails .reversal_time{pointer-events:none!important;z-index:2!important;position:absolute!important;top:31px!important;left:auto!important;right:10px!important}.fleetDetails.detailsClosed .reversal_time{pointer-events:all!important;top:14px!important;right:0!important}.ogl_timeBlock{grid-gap:78px;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:repeat(2,1fr);align-items:center;display:grid}.ogl_timeBlockLeft,.ogl_timeBlockRight{-webkit-border-radius:3px;border-radius:3px;grid-template-columns:70px 70px auto;justify-content:start;padding:1px;display:grid}.ogl_timeBlockRight{text-align:right;grid-template-columns:auto 70px 70px;justify-content:end}.ogl_timeBlock>div>*{text-align:inherit!important;width:auto!important;margin:0!important;padding:0!important;line-height:14px!important;position:relative!important;top:0!important;left:0!important}.ogl_timeBlock .tooltip{color:inherit!important}.ogl_timeBlock .originData,.ogl_timeBlock .destinationData{grid-gap:5px;justify-content:center;display:flex}.ogl_timeBlock .originPlanet,.ogl_timeBlock .destinationPlanet,.ogl_timeBlock .originCoords,.ogl_timeBlock .destinationCoords{padding:0!important;position:relative!important;left:0!important}.detailsOpened .destinationPlanet,.detailsClosed .destinationPlanet,.detailsOpened .originPlanet{width:auto!important}.ogl_actionsBlock{background:var(--tertiary);grid-gap:5px;z-index:2;-webkit-border-radius:3px;border-radius:3px;grid-template-columns:repeat(2,1fr);justify-content:center;align-items:center;padding:2px;display:grid;position:absolute;top:-5px;left:50%;transform:translate(-50%);box-shadow:0 3px 5px -2px #000}.ogl_actionsBlock *{justify-self:center;width:18px!important;margin:0!important;padding:0!important;position:relative!important;top:0!important;left:0!important}.ogl_actionsBlock .ogl_icon[class*=ogl_mission]:not(.ogl_mission18):before{background-size:212px!important}.ogl_actionsBlock .ogl_icon[class*=ogl_mission]:before{width:18px;margin:0}.fleetDetails .allianceName{top:-17px!important;bottom:auto!important;left:auto!important;right:3px!important}.ogl_phalanxLastRefresh{color:var(--ogl);margin-left:30px;font-size:11px}.ogl_universeName{color:#aeaac1;pointer-events:none;text-align:right;width:138px;font-size:12px;font-weight:700;line-height:12px;position:absolute;top:102px}.ogl_universeInfoTooltip{line-height:1.4}.ogl_universeInfoTooltip div{color:var(--amber);float:right;text-indent:10px;font-size:11px}.ogl_popup .ogl_frameSelector{grid-gap:5px;grid-template-columns:repeat(6,1fr);margin-bottom:10px;display:grid}.ogl_popup .ogl_frameSelector .ogl_button{min-width:80px}.ogl_popup .ogl_frameSelector .ogl_button.ogl_active{box-shadow:0 0 0 2px var(--ogl)}.ogl_ptreContent{grid-gap:10px;grid-template-columns:auto auto;display:grid}.ogl_ptreContent b{color:#ff4646;border-top:1px solid #1b222b;border-bottom:1px solid #1b222b;justify-content:center;align-items:center;margin-bottom:10px;padding:5px 0;font-size:12px;display:flex}.ogl_ptreContent b .material-icons{margin-right:5px;font-size:16px!important}.ogl_ptreContent h3{text-align:center;grid-column:1/-1;padding:8px;font-size:18px}.ogl_ptreContent hr{background:#151e28;border:none;grid-column:1/-1;width:100%;height:2px}.ogl_ptreActivityBlock,.ogl_ptreBestReport{background:rgba(0,0,0,.2);-webkit-border-radius:9px;border-radius:9px;padding:10px}.ogl_ptreLegend{color:var(--blue);text-align:left;margin-top:20px;font-size:10px}.ogl_ptreActivities [data-check]{background:currentColor;border:3px solid;-webkit-border-radius:50%;border-radius:50%;align-self:center;width:0;height:0;padding:4px}.ogl_ptreActivities [data-check].ogl_active{background:0 0}.ogl_ptreActivities>span{color:var(--red)}.ogl_ptreActivities>div{grid-gap:5px;grid-template-columns:repeat(12,1fr);display:grid}.ogl_ptreActivities>div>*{background:var(--secondary);color:#656f78;-webkit-border-radius:2px;border-radius:2px;align-items:center;height:45px;padding:3px;display:grid}.ogl_ptreActivities>div>*>*{margin:auto;display:inline-block}.ogl_ptreActivities .ptreDotStats{width:30px;height:30px;position:relative}.ogl_ptreContent{text-align:center}.ogl_ptreBestReport>div:first-child{padding:10px}.ogl_checked{justify-content:center;align-items:center;width:24px;height:28px;display:flex;position:absolute;bottom:5px;right:5px;color:#4d5e78!important;font-size:20px!important}.ogl_log>div:not(.ogl_close):not(.ogl_share){border-bottom:1px solid #20262c;grid-template-columns:100px 100px 300px;margin-top:5px;padding-bottom:5px;display:grid}.ogl_log h2{grid-column:1/-1}.ogl_ptreActionIcon{justify-content:center;align-items:center;display:inline-flex}.ogl_ptreActionIcon i{color:inherit;font-size:12px!important}.ogl_ptreActionIcon i.ogl_active{animation:1.5s linear infinite blink}@keyframes blink{50%{opacity:0}}.ogl_leftMenuIcon{user-select:none;text-align:center;background:linear-gradient(#1b2024 50%,#000 50%);-webkit-border-radius:4px;border-radius:4px;height:27px;margin-right:11px;display:block;width:27px!important}.ogl_leftMenuIcon a{justify-content:center;align-items:center;height:100%;color:#353a3c!important;display:flex!important}.ogl_leftMenuIcon a i{font-size:21px!important;line-height:27px!important}.ogl_leftMenuIcon a:hover{color:#d39343!important}.ogl_resourceBoxStorage{pointer-events:none;width:100%;font-size:10px;display:none;position:absolute;top:12px;left:0}#resources:hover .ogl_resourceBoxStorage{display:block}#resources:hover .resource_tile .resourceIcon.metal{box-shadow:inset 0 0 0 20px rgba(0,0,0,.8)}#resources:hover .resource_tile .resourceIcon.crystal{box-shadow:inset 0 0 0 20px rgba(0,0,0,.8)}#resources:hover .resource_tile .resourceIcon.deuterium{box-shadow:inset 0 0 0 20px rgba(0,0,0,.8)}.ogl_manageData .ogl_grid{grid-gap:3px;display:grid}.ogl_manageData .ogl_button{grid-gap:6px;justify-content:center;align-items:center;width:100%;padding:11px 0;display:grid;line-height:18px!important}.ogl_manageData .ogl_button .material-icons{font-size:22px!important}.ogl_manageData .ogl_button.ogl_danger:hover{color:var(--ogl)!important}.ogl_manageData .ogl_dangerZone{border:2px solid var(--red);background:#241313;-webkit-border-radius:3px;border-radius:3px;margin-top:14px;padding:16px}.ogl_manageData .ogl_dangerZone .ogl_button{width:240px}.ogl_manageData hr{background:#151e28;border:none;grid-column:1/-1;width:100%;height:2px}.chat_msg .msg_date,.detail_msg .msg_date{position:absolute}.ogl_acsInfo .value span{margin-left:5px}.ogl_blackHoleButton{width:28px;position:absolute;top:0;right:-3px;transform:translate(100%);font-size:16px!important}.ogl_blackhole .ogl_button{float:right;width:70px;margin-top:10px}.ogl_buildIconList{grid-gap:2px;pointer-events:none;display:flex;position:absolute;bottom:2px;left:23px}.ogl_buildIcon{color:red;background:currentColor;-webkit-border-radius:2px;border-radius:2px;width:10px;height:3px;box-shadow:0 0 2px #000;padding:0!important}.ogl_buildIcon[data-type=building]{color:#ff8200}.ogl_buildIcon[data-type=research]{color:#32fb2f}.ogl_buildIcon[data-type=ship]{color:#ffeb00}.ogl_buildIcon[data-type=lfbuilding]{color:#ff79bd}.ogl_buildIcon[data-type=lfresearch]{color:#42afff}.smallplanet .constructionIcon{display:none!important}.ogl_buildList:has(li){margin-top:5px}.ogl_buildList li{align-items:center;display:flex}.ogl_buildList li span{max-width:100px;display:inline-block}.ogl_buildList .material-icons{margin:0 7px}.ogl_buildList .material-icons:first-child{margin:0 4px 0 0;font-size:8px!important}.ogl_buildList b{color:var(--amber);font-size:12px;font-weight:700}[data-debug]{position:relative}[data-debug]:after{content:attr(data-debug);opacity:.8;text-shadow:1px 1px #000;background:rgba(0,0,0,.7);width:max-content;display:block;position:absolute;top:12px;left:0;color:#ff0!important}.ogl_datePicker{grid-gap:10px;user-select:none;grid-template-columns:repeat(3,1fr);display:grid!important}.ogl_datePicker .ogl_dateItem{justify-content:center;align-items:center;font-size:14px;display:flex}.ogl_datePicker .material-icons{font-size:16px!important}#jumpgate #selecttarget select{visibility:visible!important;display:block!important}#jumpgate #selecttarget .dropdown{display:none!important}#jumpgate select{padding:2px!important;font-size:12px!important}.ogl_boardMessageTab{padding:7px 8px 0;position:relative}.ogl_boardMessageTab .newMessagesCount{color:#fff;text-align:center;background-color:#242d37;border:1px solid #40c4c1;-webkit-border-radius:8px;border-radius:8px;min-width:16px;height:16px;padding:0 2px;font-size:9px;line-height:16px;position:absolute;top:-3px;right:-3px;box-shadow:0 2px 4px rgba(0,0,0,.75)}.ogl_boardMessageTab.marker{background:url(https://gf1.geo.gfsrv.net/cdn69/112960c1ace80c7dcb03ca88d4b6fc.png) no-repeat}.ogl_boardMessageTab .tabLabel{margin-top:6px}.ogl_boardMessageTab .material-icons{color:transparent;background:linear-gradient(#d7dfe5 50%,#d4d9dd 50%) text;justify-content:center;align-items:center;width:100%;height:100%;margin-bottom:4px;display:flex;font-size:38px!important}.ogl_boardMessageTab .tabImage{cursor:pointer!important;background:linear-gradient(135deg,#375063 33.33%,#23394a 33.33%,#23394a 50%,#375063 50%,#375063 83.33%,#23394a 83.33%,#23394a 100%) 0 0/3px 3px!important;border:1px solid #385365!important;border-left:2px solid #3c596c!important;border-right:2px solid #3c596c!important;-webkit-border-radius:7px!important;border-radius:7px!important;width:48px!important;height:50px!important;margin-top:1px!important;text-decoration:none!important;position:relative!important;box-shadow:inset 0 0 10px 6px #1c2831,0 0 1px 1px #000!important}.ogl_boardMessageTab .tabImage:hover{filter:brightness(1.2)}.ogl_boardMessageTab .tabImage:before{content:"";filter:blur(.5px);opacity:.6;background:#395467;-webkit-border-radius:6px;border-radius:6px;height:calc(50% + 2px);position:absolute;top:-2px;left:0;right:0}.ogl_boardMessageTab .tabImage:after{content:"";filter:blur(1px);opacity:.6;background:#395467;-webkit-border-radius:7px;border-radius:7px;height:4px;position:absolute;bottom:2px;left:3px;right:3px}.ogl_boardMessageTab.ui-tabs-active .marker{top:-9px!important;left:-10px!important}#oglBoardTab *{max-width:100%}#oglBoardTab .msg{padding:10px}#oglBoardTab .msg_content{margin-top:10px;padding:0}#oglBoardTab .msg_content>ul li{margin-bottom:10px}#oglBoardTab .msg_title{line-height:15px;display:inline-block!important}#oglBoardTab .msg_title:hover{color:#fff;cursor:pointer;text-decoration:underline}#oglBoardTab .msg_title i{color:var(--pink)}#oglBoardTab .spoilerBox{display:none!important}.ogl_sidenote{color:#aaa;font-style:italic}.ogl_shipDataInfo .material-icons{color:#7ca8ad;vertical-align:middle;font-size:18px!important}.ogl_shipDataInfo b{color:var(--ogl)}.ogl_totalRequired{background:var(--primary);-webkit-border-radius:3px;border-radius:3px;margin-top:10px;padding:10px}.ogl_totalRequired h3{pointer-events:none;text-align:center}.ogl_totalRequired h3:after{content:none}.ogl_totalRequired .ogl_200:before{visibility:hidden}.ogl_totalRequired .ogl_grid{display:flex}.ogl_totalRequired .ogl_icon{grid-gap:8px;text-align:center;display:grid}.ogl_totalRequired .ogl_icon:before{margin:auto}.shipyardSelection{background:var(--primary);padding:10px;width:auto!important}.ogl_timeBox{margin-top:5px;display:block}.ogl_lineBreakFlex{flex-basis:100%;height:0}#messagecontainercomponent .msgHead{padding:5px 5px 0 8px!important}.msg:not(:has([data-raw-messagetype="65"],[data-raw-messagetype="68"])) .content-box{display:none!important}.msg:has([data-raw-messagetype="25"]){box-shadow:inset 3px 0 var(--mission1)!important}.msg:has([data-raw-messagetype="41"]){box-shadow:inset 3px 0 var(--mission15)!important}.msg:has([data-raw-messagetype="61"]){box-shadow:inset 3px 0 var(--lifeform)!important}.msg:has([data-raw-messagetype="32"]){box-shadow:inset 3px 0 var(--mission8)!important}.msg:has([data-raw-messagetype="34"]):has(.ogl_battle){box-shadow:inset 3px 0 var(--mission3)!important}.msg:has([data-raw-messagetype="35"]) .content-box{display:block!important}.msg:has([data-raw-messagetype="54"]) .content-box{display:block!important}.detail_msg .loot-row{background:#1f252e;-webkit-border-radius:5px;border-radius:5px;padding:5px}.ogl_spytable .fleetAction{pointer-events:none!important;margin-left:0!important;right:0!important}#messagecontainercomponent .msg{margin-bottom:3px!important}.messagesHolder .msgWithFilter .msgFilteredHeaderRow{border-bottom:1px solid #000;box-shadow:none!important}#messagecontainercomponent .ogl_spytable:has(.ogl_spyLine:not(.ogl_spySum))+.messageContent .tabsWrapper:has(.active[data-subtab-id="20"]){border-left:1px solid #000;border-right:1px solid #000;-webkit-border-radius:5px;border-radius:5px;width:650px;position:absolute;top:114px;left:10px;overflow:hidden}.tippy-box{-webkit-border-radius:8px!important;border-radius:8px!important;box-shadow:0 0 20px -5px #000,0 0 5px 2px rgba(0,0,0,.5)!important}.tippy-content{background:var(--tertiary)!important;border:none!important;-webkit-border-radius:5px!important;border-radius:5px!important;padding:20px!important;font-size:11px!important}.tippy-content hr,.ogl_notification hr{background:#1e252e;border:none;grid-column:1/-1;width:100%;height:2px}.tippy-arrow{color:#171c24!important}.tippy-box[data-animation=pop][data-state=hidden]{opacity:0}.tippy-box[data-animation=pop][data-state=hidden][data-placement^=left]{transform:translate(20px)}.tippy-box[data-animation=pop][data-state=hidden][data-placement^=right]{transform:translate(-20px)}.tippy-box[data-animation=pop][data-state=hidden][data-placement^=bottom]{transform:translateY(-20px)}.tippy-box[data-animation=pop][data-state=hidden][data-placement^=top]{transform:translateY(20px)}* .status_abbr_inactive{color:var(--inactive)!important}* .status_abbr_longinactive{color:var(--longInactive)!important}* .status_abbr_banned{color:var(--banned)!important}* .status_abbr_vacation{color:var(--vacation)!important}* .status_abbr_honorableTarget{color:var(--honorable)!important}[data-status-tag]:not([data-status-tag=false]):before{content:"("attr(data-status-tag)")";opacity:.75;white-space:nowrap;margin-right:2px}.ogl_highlight{color:var(--amber)}.ogl_oldScore{font-weight:400}.ogl_oldScore em{-webkit-border-radius:2px;border-radius:2px;padding:1px;font-style:normal}#highscoreContent form #content{box-sizing:border-box!important;padding:10px!important}#highscoreContent div.content table{width:100%!important}#highscoreContent #ranks tbody tr{background:#151920!important;border-bottom:2px solid #0d1014!important}#highscoreContent #ranks tbody tr.myrank{background:linear-gradient(192deg,#23575c,#1c2a34 70%)!important}#highscoreContent #ranks tbody tr.allyrank{background:linear-gradient(192deg,#2f366a,#181a2c 70%)!important}#highscoreContent #ranks tbody tr.buddyrank{background:linear-gradient(192deg,#672f6a,#181a2c 70%)!important}#highscoreContent #ranks td{background:0 0!important;border:none!important;padding:0!important}#highscoreContent #ranks .playername{font-size:11px!important;font-weight:400!important}#highscoreContent #ranks .ally-tag,#highscoreContent #ranks .honorRank{margin-right:0!important;font-size:11px!important}#highscoreContent #ranks .highscoreNameHolder:not(:has(.honorRank)){margin-left:19px}#highscoreContent #ranks .movement{text-align:left!important;font-size:10px!important}#highscoreContent #ranks profile-picture{width:32px!important;height:32px!important}#highscoreContent #ranks profile-picture *{max-width:100%!important;max-height:100%!important}#highscoreContent #ranks .highscoreNameFieldWrapper{height:34px!important}#highscoreContent #ranks .honorScore{display:none!important}#highscoreContent #ranks tr.expandedRow{height:auto!important}#highscoreContent #ranks thead .score{font-weight:400}#highscoreContent #ranks .score{color:#748999!important;padding-right:5px!important;font-size:11px!important}#highscoreContent #ranks .highscorePositionIcon{background-size:50%!important;height:28px!important}#highscoreContent #ranks .position{text-align:center!important}#highscoreContent #ranks.allyHighscore tbody .name{grid-gap:4px;line-height:34px;display:flex;padding-left:14px!important}.ogl_moreGalaxyInfo{grid-gap:10px;align-items:center;margin:auto 14px auto auto;display:flex}.ogl_moreGalaxyInfo .ogl_separator{background:#2e3840;-webkit-border-radius:50%;border-radius:50%;align-self:center;width:1px;height:1px;padding:2px}.ogl_lastGalaxyRefresh,.ogl_lastDiscovery{grid-gap:4px;align-items:center;font-size:11px;display:flex}.ogl_lastGalaxyRefresh .material-icons{color:var(--time);font-size:14px!important}.ogl_systemState.tooltip{color:#263a4a;font-size:16px!important}.ogl_lastDiscovery{color:var(--lifeform)!important}.ogl_lastDiscovery.ogl_active{box-shadow:none}.ogl_infoStats b{color:var(--ogl)}.ogl_statsRecapHeader{font-size:11px!important}.ogl_limiterSettings .ogl_grid{grid-gap:14px;grid-auto-flow:column;margin-top:40px;display:grid}.ogl_limiterColumn{grid-gap:3px;background:linear-gradient(266deg,#252e3a,#171c24 70%);border:2px solid #1a202d;-webkit-border-radius:4px;border-radius:4px;padding:12px;display:grid}.ogl_limiterColumn .ogl_header{color:#fff;background:linear-gradient(45deg,#161927,#2d3447);-webkit-border-radius:5px;border-radius:5px;justify-content:center;align-items:center;height:40px;margin-top:-38px;margin-bottom:55px;font-size:14px;display:grid;box-shadow:2px 3px 9px rgba(0,0,0,.74)}.ogl_limiterColumn:first-child .ogl_header{opacity:0}.ogl_limiterColumn .ogl_header>div{align-items:center;display:flex}.ogl_limiterColumn .ogl_header .material-icons{margin-right:5px;font-size:17px!important;line-height:17px!important}.ogl_limiterColumn .ogl_limiterColumnAction{box-sizing:border-box;background:#11161a;border:2px solid #202934;-webkit-border-radius:5px;border-radius:5px;gap:2px;width:100%;padding:2px;display:flex;position:absolute;top:46px}.ogl_limiterSettings .ogl_icon{height:25px;padding:0}.ogl_limiterSettings .ogl_icon:before{width:33px;height:20px;margin:0}.ogl_limiterSettings input.ogl_inputField{width:160px!important;height:25px!important;padding:4px 6px!important}.ogl_syncLimiter{justify-content:center;align-items:center;width:100%;padding:4px;display:inline-flex}.ogl_syncLimiter.ogl_disabled{opacity:1;filter:grayscale()invert()brightness(.4)}.ogl_limiterColumn .ogl_header .ogl_button .material-icons{margin:0}#links .leftmenu li{white-space:nowrap}.ogl_accountProduction{grid-gap:4px;grid-template-columns:repeat(3,1fr);margin-top:14px;display:grid}.ogl_accountProduction .ogl_icon{background:var(--secondary);min-width:120px;padding:3px 6px 3px 3px}.ogl_accountProduction .ogl_icon:before{width:24px;height:20px;margin-right:auto}.ogl_accountRank{text-align:center;background:#14171e;border:3px solid #171c23;-webkit-border-radius:7px;border-radius:7px;margin:10px;padding:10px;display:grid;position:relative}.ogl_accountRank .material-icons{color:var(--ogl);font-size:30px!important}.ogl_accountRank h3{margin:5px auto;font-size:18px}.ogl_accountRank.ogl_accountEconomy .material-icons{color:#3eebff}.ogl_accountRank.ogl_accountFleet .material-icons{color:#ff403e}.ogl_accountRank.ogl_accountLifeform .material-icons{color:#b351ed}.ogl_accountRank.ogl_accountLifeform .ogl_accountProduction{grid-template-columns:repeat(2,1fr)}.ogl_accountRanking{background:var(--secondary);color:#8498bb;-webkit-border-radius:3px;border-radius:3px;padding:6px;font-weight:700;position:absolute;top:5px;right:5px}.ogl_accountScore{color:#9d9d9d;margin-top:4px;font-size:14px;font-style:italic}.ogl_clockNotif{background:var(--tertiary);justify-content:center;align-items:center;width:19px;padding:0;display:flex;position:absolute;right:0;box-shadow:0 0 0 1px #000;color:#4c6373!important;line-height:normal!important}.content-box-s .ogl_clockNotif{top:5px;right:18px}.ogl_clockNotif:before{content:"\\f170";font-family:Material Icons;font-size:16px!important}.ogl_clockNotif:hover{box-shadow:0 0 0 2px var(--ogl);color:#4c6373!important}.ogl_clockNotif.ogl_active{color:var(--ogl)!important}.ogl_clockNotif.ogl_active.ogl_altered{color:#b556fb!important}.ogl_accountContainer{background:#0c0d14;-webkit-border-radius:0 0 7px 7px;border-radius:0 0 7px 7px;padding:7px;display:grid}.ogl_accountSummary{display:grid}.ogl_accountSummary .ogl_tabs{grid-template-columns:repeat(5,1fr);font-size:12px;font-weight:700;display:grid}.ogl_accountSummary .ogl_tabs+.ogl_tabs{grid-gap:4px;background:#0c0d14;border-top:2px solid #191f2b;grid-template-columns:repeat(6,1fr)}.ogl_accountSummary .ogl_tab{color:#627799;cursor:pointer;grid-gap:6px;text-align:center;text-transform:capitalize;justify-content:center;align-items:center;min-width:125px;padding:14px 0 7px;display:grid}.ogl_accountSummary .ogl_tabs+.ogl_tabs .ogl_tab{background:linear-gradient(#405064,#2d3743 2px,#181e25);-webkit-border-radius:3px;border-radius:3px;margin:5px 0 0 5px;padding:7px 0;font-size:11px;display:flex}.ogl_accountSummary .ogl_tab:hover{color:#80b6fb}.ogl_accountSummary .ogl_tab.ogl_active{color:var(--ogl);text-shadow:0 0 4px var(--ogl);background:linear-gradient(#28323e,#1c2028 max(5%,5px),#121418 max(16%,24px),#0f1014);-webkit-border-radius:7px 7px 0 0;border-radius:7px 7px 0 0}.ogl_accountSummary .ogl_tab .material-icons{font-size:20px!important}.ogl_accountEmpire{grid-gap:3px}.ogl_accountEmpire .ogl_line{grid-gap:3px;grid-template-columns:90px 24px 24px 100px 100px 60px 30px 130px 130px 130px;height:26px;font-size:11px;display:grid}.ogl_accountEmpire .ogl_line>*{background:var(--secondary);color:#a0abbf;-webkit-border-radius:2px;border-radius:2px;justify-content:center;align-items:center;display:flex;overflow:hidden}.ogl_accountEmpire .ogl_line>:has(img){background:0 0}.ogl_accountEmpire .ogl_line>:before{margin:auto}.ogl_accountEmpire .ogl_upgrade{color:var(--ogl);margin-left:3px;font-size:11px}.ogl_accountEmpire .ogl_line strong{margin-left:12px;font-size:14px;font-weight:700}.ogl_accountEmpire .ogl_line small{margin-left:auto;margin-right:12px}.ogl_accountEmpire img{width:24px}.ogl_accountGraph{border-bottom:4px solid #21252e;justify-content:center;align-items:flex-end;height:50px;margin-bottom:30px;display:flex}.ogl_accountGraph .ogl_accountBar{background-color:#3498db;align-self:flex-end;align-items:center;width:15%;margin:0 2px;position:relative}.ogl_accountGraph .ogl_accountBar:first-child{background:var(--ogl)}.ogl_accountGraph .ogl_accountBar:nth-child(2){background:#3eebff}.ogl_accountGraph .ogl_accountBar:nth-child(3){background:#21d19f}.ogl_accountGraph .ogl_accountBar:nth-child(4){background:#b351ed}.ogl_accountGraph .ogl_accountBar:nth-child(5){background:#ff403e}.ogl_accountGraph .ogl_accountBar:nth-child(6){background:#f96e46}.ogl_accountGraph .ogl_accountBar:first-child label{color:var(--ogl)}.ogl_accountGraph .ogl_accountBar:nth-child(2) label{color:#3eebff}.ogl_accountGraph .ogl_accountBar:nth-child(3) label{color:#21d19f}.ogl_accountGraph .ogl_accountBar:nth-child(4) label{color:#b351ed}.ogl_accountGraph .ogl_accountBar:nth-child(5) label{color:#ff403e}.ogl_accountGraph .ogl_accountBar:nth-child(6) label{color:#f96e46}.ogl_accountGraph label{text-align:center;width:100%;margin-top:10px;font-family:Material Icons;font-size:18px;position:absolute;top:100%;left:0}.ogl_accountGraph label:after{color:#aaa;content:attr(data-value);margin-top:3px;font-family:Verdana,Arial,SunSans-Regular,sans-serif;font-size:10px;display:block}.ogl_accountMain{grid-template-columns:repeat(2,1fr)}.ogl_accountShips{grid-gap:3px;font-size:12px}.ogl_accountShips .ogl_line{grid-gap:3px;display:flex}.ogl_accountShips .ogl_line>*{background:var(--secondary);color:#a0abbf;-webkit-border-radius:3px;border-radius:3px;flex-grow:1;justify-content:center;align-items:center;width:42px;height:24px;display:flex}.ogl_accountShips .ogl_line [data-galaxy]{color:#fff}.ogl_accountShips .ogl_line>:first-child{width:70px;font-size:11px}.ogl_accountShips .ogl_line>[data-amount="0"]{opacity:.2}.ogl_accountShips .ogl_icon{padding:0!important}.ogl_accountShips .ogl_icon:before{margin:auto!important}.ogl_accountShips .ogl_line:last-child{border-top:2px solid #24272f;padding-top:3px}.ogl_accountEmpire .ogl_line:last-child{border-top:2px solid #24272f;padding-top:3px}.recomission[disabled]{pointer-events:none}.reCommissionButton>[disabled]{pointer-events:none}#technologydetails[data-technology-id="36"] .description .txt_box{width:fit-content!important;width:-moz-fit-content!important;position:absolute!important;top:0!important;right:5px!important}#technologydetails .description .repair_order{width:215px;display:block}#technologydetails .description #wreckfield-btns{grid-gap:5px;flex-wrap:wrap;position:absolute;top:25px;right:0;display:flex!important}#wreckfield-btns .ogl_button{border:#030a14;align-items:center;max-width:200px;margin-left:auto;padding:7px 11px;font-size:12px;display:flex;line-height:14px!important}#wreckfield-btns .ogl_button:hover{box-shadow:0 0 0 2px #fff}#wreckfield-btns .ogl_button+.ogl_button{margin-left:0;color:var(--ogl)!important}#wreckfield-btns>:not(.ogl_button){margin-left:auto}#wreckfield-btns:not(.ogl_active){pointer-events:none;visibility:hidden;display:none}#wreckfield-btns .btn:not(.ogl_active){pointer-events:none;visibility:hidden;display:none}.complex_action[class*=wreckfield_]{border:none!important}.complex_action[class*=wreckfield_] #description{font-size:10px!important}.complex_action[class*=wreckfield_] #description>a{display:none}.complex_action[class*=wreckfield_] hr{background:#1e252e;border:none;width:100%;height:2px}.ogl_crawlerInfo{box-sizing:border-box;color:#97b4db;pointer-events:none;background:rgba(0,0,0,.8);width:96px;height:82px;padding:5px 0;font-size:11px;display:none;position:absolute;top:2px;right:6px}#shipyard .ogl_crawlerInfo{width:76px;height:61px;padding:0;font-size:10px;top:2px;right:2px}.technology:has(.ogl_crawlerInfo):hover .ogl_crawlerInfo{display:block}.ogl_crawlerInfo>div{justify-content:center;align-items:center;display:flex}.ogl_crawlerInfo .material-icons{color:#fff;margin:0 4px;font-size:12px!important}#shipyard .ogl_crawlerInfo .material-icons{margin:0 1px;font-size:11px!important}#commandercomponent #lifeform .lifeform-item-icon span{color:#fff;text-shadow:1px 1px 3px #000;background:rgba(0,0,0,.7);-webkit-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;padding:3px 5px;font-weight:700;position:absolute;bottom:-1px;right:-1px}#commandercomponent #lifeform:hover{transform:scale(1)!important}.ogl_lfBonusesLink{justify-content:center;align-items:center;font-family:Material icons;position:absolute;top:0;right:100%;color:var(--lifeform)!important;background:0 0!important;border:none!important;width:25px!important;height:36px!important;font-size:18px!important;display:flex!important}.ogl_lfBonusesLink:hover{color:var(--ogl)!important}body[data-minipics=true] .maincontent>div header{height:34px!important}body[data-minipics=true] .maincontent .planet-header{height:34px!important}body[data-minipics=true] .maincontent #overviewcomponent #planet{height:auto!important;min-height:208px!important;position:relative!important}body[data-minipics=true] .maincontent #overviewcomponent #detailWrapper{height:auto!important;min-height:208px!important;position:relative!important}body[data-minipics=true] .maincontent #technologydetails_wrapper:not(.slide-down){position:relative!important}body[data-minipics=true] .maincontent #detail.detail_screen{height:300px!important;position:relative!important}body[data-menulayout="1"] #headerbarcomponent{width:1016px!important}body[data-menulayout="1"] #commandercomponent{transform:translate(25px)}body[data-menulayout="1"] #planetbarcomponent #myPlanets{width:172px!important}body[data-menulayout="1"] #planetbarcomponent #myWorlds{width:172px!important}body[data-menulayout="1"] .smallplanet .planet-name{left:28px!important}body[data-menulayout="1"] .smallplanet .planet-koords{left:28px!important}body[data-menulayout="2"] #headerbarcomponent{width:1016px!important}body[data-menulayout="2"] #commandercomponent{transform:translate(25px)}body[data-menulayout="2"] #planetbarcomponent #myPlanets{width:172px!important}body[data-menulayout="2"] #planetbarcomponent #myWorlds{width:172px!important}body[data-menulayout="2"] .smallplanet .planet-name{left:28px!important}body[data-menulayout="2"] .smallplanet .planet-koords{left:28px!important}body[data-menulayout="1"] .smallplanet{grid-template-columns:74% auto}body[data-menulayout="1"] .smallplanet .ogl_refreshTimer.ogl_moon{left:74%}body[data-menulayout="1"] .smallplanet .ogl_available{display:none!important}body[data-menulayout="2"] .smallplanet{grid-template-columns:60% auto}body[data-menulayout="2"] .smallplanet .ogl_refreshTimer.ogl_moon{left:60%}body[data-menulayout="2"] .smallplanet .planet-name{opacity:0!important}body[data-menulayout="2"] .smallplanet .planet-koords{opacity:0!important}body[data-sidepanel=true] .ogl_side{right:auto;transform:translate(-100%)}body[data-sidepanel=true] .ogl_side.ogl_active{transform:translate(-0%)}`);
if(typeof window?.GM_getTab == typeof undefined)
{
window.GM_getTab = tab =>
{
const params = JSON.parse(GM_getValue('ogl_tab') || '{}');
tab(params);
}
}
if(typeof window?.GM_saveTab == typeof undefined)
{
window.GM_saveTab = data =>
{
GM_setValue('ogl_tab', JSON.stringify(data || {}));
}
}
if(typeof window?.GM_addStyle === typeof undefined)
{
window.GM_addStyle = css =>
{
const style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.textContent = css;
document.head.appendChild(style);
}
}
if(typeof window?.GM_info == typeof undefined)
{
window.GM_info = {};
window.GM_info.script = {};
window.GM_info.script.name = 'OGLight GM_less';
window.GM_info.script.version = oglVersion;
window.GM_info.script.downloadURL = 'https://openuserjs.org/install/nullNaN/OGLight.user.js';
}
if(typeof window?.GM_xmlhttpRequest == typeof undefined)
{
window.GM_xmlhttpRequest = () => {};
}
if(typeof window?.GM_notification == typeof undefined)
{
window.GM_notification = () => {};
}
class OGLight
{
constructor(params)
{
// get the account ID in cookies
let cookieAccounts = document.cookie.match(/prsess\_([0-9]+)=/g);
// purge cookies to prevent session conflict
if(cookieAccounts?.length > 1)
{
const allCookies = document.cookie.split(';');
for(let i = 0; i < allCookies.length; i++)
{
let cookie = allCookies[i].trim();
const cookieName = cookie.split('=')[0];
if(cookieName.startsWith('prsess_'))
{
document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/';
}
}
cookieAccounts = document.cookie.match(/prsess\_([0-9]+)=/g);
}
// force relogin
if(!cookieAccounts)
{
alert('You have been signed out due to a session conflict. Please log in again to continue.');
window.location.href = "index.php?page=logout";
return;
}
const accountID = cookieAccounts[cookieAccounts.length-1].replace(/\D/g, '');
//console.log(Util.hash('test'))
// OGL database
//this.DBName = `${this.server.lang}_${this.server.id}_${this.account.id}`;
this.DBName = `${accountID}-${window.location.host.split('.')[0]}`;
this.db = this.load();
//this.db = new Database(this.DBName);
// fix beta old DB
if(!GM_getValue(this.DBName) && GM_getValue(window.location.host))
{
GM_setValue(this.DBName, GM_getValue(window.location.host));
GM_deleteValue(window.location.host);
window.location.reload();
}
const dbDefaults =
{
lastServerUpdate: 0,
lastEmpire0Update: 0,
lastEmpire1Update: 0,
lastLFBonusUpdate: 0,
lastProductionQueueUpdate: 0,
udb: {}, // players
pdb: {}, // planets
tdb: {}, // targets
myPlanets: {},
activeItems: [],
dataFormat: 0,
tags:
{
red: true,
orange: true,
yellow: true,
lime: true,
green: true,
blue: true,
dblue: true,
violet: true,
magenta: true,
pink: true,
brown: true,
gray: true,
none: false
},
lastPinTab: 'miner',
shipsCapacity: {},
spytableSort: 'total',
lastTaggedInput: [],
lastPinnedList: [],
initialTime: Date.now(),
/*limiters:
{
planet:{ resourcesActive:true, shipsActive:true, foodActive:true },
moon:{ resourcesActive:true, shipsActive:true, foodActive:true },
jumpgate:{ shipsActive:true },
},*/
fleetLimiter:
{
data: {},
jumpgateData: {},
moonData: {},
shipActive: false,
resourceActive: false,
jumpgateActive: false
},
keepEnoughCapacityShip: 200,
keepEnoughCapacityShipJumpgate: 200,
spyProbesCount: 6,
configState:
{
fleet: true,
general: true,
expeditions: true,
stats: true,
messages: true,
data: true,
PTRE: true,
interface: true
},
browserNotificationList: {},
lastAccountTab: {},
lastBoardPosts: [0, 0, 0],
options:
{
defaultShip: 202,
defaultMission: 3,
resourceTreshold: 300000,
ignoreConsumption: false,
ignoreExpeShipsLoss: false,
useClientTime: false,
displayMiniStats: 'day',
collectLinked: false,
expeditionValue: 0,
expeditionBigShips: [204, 205, 206, 207, 215],
expeditionRandomSystem: 0,
expeditionRedirect: false,
expeditionShipRatio: 100,
displayPlanetTimers: false,
reduceLargeImages: false,
colorblindMode: false,
showMenuResources: 0,
autoCleanReports: false,
autoCleanCounterSpies: false,
tooltipDelay: 400,
spyIndicatorDelay: 3600000,
debugMode: false,
sim: false,
boardTab: true,
msu: '3:2:1',
disablePlanetTooltips: false,
displaySpyTable: true,
shortcutsOnRight: false,
sidePanelOnLeft: false,
spyTableRules: [],
spyTableMSU: false,
keyboardActions:
{
menu: '²',
previousPlanet: 'i',
nextPlanet: 'o',
nextPinnedPosition: 'm',
fleetRepeat: 'p',
fleetSelectAll: 'a',
fleetReverseAll: 'r',
fleetQuickCollect: 'q',
expeditionSC: 's',
expeditionLC: 'l',
expeditionPF: 'f',
quickRaid: 't',
fleetResourcesSplit: '2-9',
galaxyUp: window.location.host.split(/[-.]/)[1] == 'fr' ? 'z' : 'w',
galaxyLeft: window.location.host.split(/[-.]/)[1] == 'fr' ? 'q' : 'a',
galaxyDown: 's',
galaxyRight: 'd',
galaxyReload: 'f',
galaxySpySystem: 'r',
backFirstFleet: 'f',
backLastFleet: 'l',
discovery: 'u',
showMenuResources: 'v'
}
}
}
this.db = Object.assign({}, dbDefaults, this.db);
this.db.options = Object.assign({}, dbDefaults.options, this.db.options || {});
this.db.options.keyboardActions = Object.assign({}, dbDefaults.options.keyboardActions, this.db.options.keyboardActions || {});
this.db.fleetLimiter = Object.assign({}, dbDefaults.fleetLimiter, this.db.fleetLimiter || {});
this.db.configState = Object.assign({}, dbDefaults.configState, this.db.configState || {});
this.db.tags = Object.assign({}, dbDefaults.tags, this.db.tags || {});
this.db.fleetLimiter.moonData = this.db.fleetLimiter.moonData || this.db.fleetLimiter.data;
this.db.options.expeditionShipRatio = Math.min(this.db.options.expeditionShipRatio, 100);
this.db.options.tooltipDelay = this.db.options.tooltipDelay !== false ? Math.max(this.db.options.tooltipDelay, 100) : 400;
// init OGL when the DOM is loaded
const checkDocumentState = () =>
{
if(document.readyState !== 'loading' && !this.isReady)
{
// checking if class Datafinder exist to prevent JS hoisting issues
if(typeof Datafinder !== 'undefined')
{
this.isReady = true;
this.init(params.cache);
}
else
{
setTimeout(() => checkDocumentState(), 100);
}
}
if(document.readyState === 'complete')
{
if(this._dom) this._dom.updatePing();
}
}
checkDocumentState();
document.addEventListener('readystatechange', () => checkDocumentState());
}
init(cache)
{
document.body.classList.add('oglight');
this.id = GM_getValue('ogl_id') || false;
this.version = GM_info.script.version.indexOf('b') > -1 ? oglVersion+betaVersion : oglVersion;
this.tooltipEvent = new Event('tooltip');
this.mode = parseInt(new URLSearchParams(window.location.search).get('oglmode')) || 0; // 1:collect, 2:collectLinked, 3:todolist, 4:reportQuickRaid, 5:expedition
this.page = new URL(window.location.href).searchParams.get('component') || new URL(window.location.href).searchParams.get('page');
this.resourcesKeys = { metal:'metal', crystal:'crystal', deut:'deuterium', food:'food', population:'population', energy:'energy', darkmatter:'darkmatter' };
this.shipsList = [202,203,204,205,206,207,208,209,210,211,213,214,215,218,219];
this.fretShips = [202, 203, 209, 210, 219];
this.ptreKey = localStorage.getItem('ogl-ptreTK') || false;
this.planetType = document.querySelector('head meta[name="ogame-planet-type"]').getAttribute('content');
this.flagsList = ['friend', 'rush', 'danger', 'skull', 'fridge', 'star', 'trade', 'money', 'ptre', 'none'];
this.server = {};
this.server.id = window.location.host.replace(/\D/g,'');
this.server.name = document.querySelector('head meta[name="ogame-universe-name"]').getAttribute('content');
this.server.lang = document.querySelector('head meta[name="ogame-language"]').getAttribute('content');
this.server.economySpeed = parseInt(document.querySelector('head meta[name="ogame-universe-speed"]').getAttribute('content'));
this.server.peacefulFleetSpeed = parseInt(document.querySelector('head meta[name="ogame-universe-speed-fleet-peaceful"]').getAttribute('content'));
this.server.holdingFleetSpeed = parseInt(document.querySelector('head meta[name="ogame-universe-speed-fleet-holding"]').getAttribute('content'));
this.server.warFleetSpeed = parseInt(document.querySelector('head meta[name="ogame-universe-speed-fleet-war"]').getAttribute('content'));
if(this.server.id == 300 && this.server.lang == 'en') return; // graveyard
this.account = {};
this.account.id = document.querySelector('head meta[name="ogame-player-id"]').getAttribute('content');
this.account.class = document.querySelector('#characterclass .sprite')?.classList.contains('miner') ? 1 : document.querySelector('#characterclass .sprite')?.classList.contains('warrior') ? 2 : 3;
this.account.name = document.querySelector('head meta[name="ogame-player-name"]').getAttribute('content');
this.account.rank = document.querySelector('#bar a[href*="searchRelId"]')?.parentNode.innerText.replace(/\D/g, '');
this.account.lang = /oglocale=([a-z]+);/.exec(document.cookie)[1];
this.account.currentPlanetID = document.querySelector('head meta[name="ogame-planet-id"]').getAttribute('content');
this.account.chatEnabled = document.querySelector('#chatBar');
this.account.hasGeologist = document.querySelector('#officers .geologist.on');
this.db.serverData = this.db.serverData || {};
this.db.serverData.serverFullID = this.db.serverData.serverFullID || this.server.id + this.server.lang;
this.db.serverData.localTimeZoneOffsetInMinutes = unsafeWindow.localTimeZoneOffsetInMinutes === 0 ? 0 : (unsafeWindow.localTimeZoneOffsetInMinutes || this.db.serverData.localTimeZoneOffsetInMinutes || 0);
this.db.serverData.serverTimeZoneOffsetInMinutes = unsafeWindow.serverTimeZoneOffsetInMinutes === 0 ? 0 : (unsafeWindow.serverTimeZoneOffsetInMinutes || this.db.serverData.serverTimeZoneOffsetInMinutes || 0);
this.db.serverData.metal = unsafeWindow.loca?.LOCA_ALL_METAL || this.db.serverData.metal || 'Metal';
this.db.serverData.crystal = unsafeWindow.loca?.LOCA_ALL_CRYSTAL || this.db.serverData.crystal || 'Crystal';
this.db.serverData.deut = unsafeWindow.loca?.LOCA_ALL_DEUTERIUM || this.db.serverData.deut || 'Deut';
this.db.serverData.food = unsafeWindow.loca?.LOCA_ALL_FOOD || this.db.serverData.food || 'Food';
this.db.serverData.dm = unsafeWindow.LocalizationStrings?.darkMatter || this.db.serverData.dm || 'Darkmatter';
this.db.serverData.energy = unsafeWindow.resourcesBar?.resources?.energy.tooltip.split('|')[0] || this.db.serverData.energy || 'Energy';
this.db.serverData.conso = unsafeWindow.loca?.LOCA_FLEET_FUEL_CONSUMPTION || this.db.serverData.conso || 'Conso';
this.db.serverData.noob = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_N || this.db.serverData.noob || 'n';
this.db.serverData.vacation = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_U || this.db.serverData.vacation || 'v';
this.db.serverData.inactive = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_I || this.db.serverData.inactive || 'i';
this.db.serverData.inactiveLong = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_I_LONG || this.db.serverData.inactiveLong || 'I';
this.db.serverData.banned = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_G || this.db.serverData.banned || 'b';
this.db.serverData.admin = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_A || this.db.serverData.admin || 'A';
this.db.serverData.outlaw = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_O || this.db.serverData.outlaw || 'o';
this.db.serverData.noob = unsafeWindow.loca?.LOCA_GALAXY_PLAYER_STATUS_N || this.db.serverData.noob || 'd';
this.db.serverData.population = 'Population';
this.db.serverData.item = 'Item';
this.db.serverData.topScore = this.db.serverData.topScore || 0;
this.db.serverData.probeCargo = this.db.serverData.probeCargo || 0;
this.db.serverData.debrisFactor = this.db.serverData.debrisFactor || 30;
if(!this.db.serverData.probeCargo) this.fretShips = [202, 203, 209, 219];
if(this.page == 'overview')
{
this.db.activeItems = [];
document.querySelectorAll('#buffBar [data-uuid]').forEach(item =>
{
const itemID = item.dataset.uuid;
if(itemID) this.db.activeItems.push(itemID);
});
}
if(this.account.lang != this.db.userLang && this.page != 'fleetdispatch' && this.page != 'intro')
{
window.location.href = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch`;
return;
}
else if(this.page != 'intro')
{
this.db.userLang = this.account.lang;
}
this.cache = cache || {};
if(window.location.href.indexOf('&relogin=1') > -1) this.cache = {};
this.playerStatus =
[
{ defaultTag:'n', serverTag:false, class:'status_abbr_active' },
{ defaultTag:'v', serverTag:this.db.serverData.vacation, class:'status_abbr_vacation' },
{ defaultTag:'I', serverTag:this.db.serverData.inactiveLong, class:'status_abbr_longinactive' },
{ defaultTag:'i', serverTag:this.db.serverData.inactive, class:'status_abbr_inactive' },
{ defaultTag:'b', serverTag:this.db.serverData.banned, class:'status_abbr_banned' },
{ defaultTag:'a', serverTag:this.db.serverData.admin, class:'status_abbr_admin' },
{ defaultTag:'o', serverTag:this.db.serverData.outlaw, class:'status_abbr_outlaw' },
{ defaultTag:'d', serverTag:this.db.serverData.noob, class:'status_abbr_noob' },
{ defaultTag:'HONORABLE', serverTag:'HONORABLE', class:'status_abbr_honorableTarget' },
]
this.updateJQuerySettings();
if(this.page != 'empire')
{
// generate a new id
if(!this.id || !this.id[0])
{
let uuid = [crypto.randomUUID(), 0];
GM_setValue('ogl_id', uuid);
this.id == uuid;
}
this.loadPlanetList();
new PopupManager(this);
this.checkDataFormat();
new DomManager(this);
new LangManager(this);
new TimeManager(this);
new FetchManager(this);
this.getPlanetData();
this.getServerData();
new UIManager(this);
new ShortcutManager(this);
new TopbarManager(this);
new FleetManager(this);
new AccountManager(this);
new TooltipManager(this);
new NotificationManager(this);
new StatsManager(this);
new GalaxyManager(this);
new MessageManager(this);
this.PTRE = new PTRE(this);
new HighscoreManager(this);
new MovementManager(this);
new TechManager(this);
new JumpgateManager(this);
new EmpireManager(this);
/*
this.excludeFromObserver = ['OGameClock', 'resources_metal', 'resources_crystal', 'resources_deuterium', 'smallplanet',
'resources_food', 'resources_population', 'resources_energy', 'resources_darkmatter', 'mmoNewsticker', 'mmoTickShow',
'tempcounter', 'counter-eventlist', 'js_duration',
'ogl_tooltip', 'ogl_tooltipTriangle', 'ogl_ready', 'ogl_addedElement'];
Util.observe(document.body, { childList:true, subtree:true, attributes:true }, mutation =>
{
let isExcluded = Array.from(mutation.target.classList).some(r=> this.excludeFromObserver.includes(r)) || this.excludeFromObserver.includes(mutation.target.id) || this.excludeFromObserver.some(r => mutation.target.id.startsWith(r));
if(!isExcluded)
{
//if(mutation.target.id) console.log(mutation.target.id)
if(mutation.target.classList.contains('ui-dialog') && mutation.target.querySelector('.detail_msg')) Util.runAsync(this._message.checkDialog, this._message);
}
}, this);*/
let universeInfo = `<ul class="ogl_universeInfoTooltip">
<li>Economy:<div>x${this.server.economySpeed}</div></li>
<li>Debris:<div>${this.db.serverData.debrisFactor}%</div></li>
<hr>
<li>Peaceful fleets:<div>x${this.server.peacefulFleetSpeed}</div></li>
<li>Holding fleets:<div>x${this.server.holdingFleetSpeed}</div></li>
<li>War fleets:<div>x${this.server.warFleetSpeed}</div></li>
</ul>`;
(document.querySelector('#pageReloader') || document.querySelector('#logoLink')).classList.add('tooltipBottom');
(document.querySelector('#pageReloader') || document.querySelector('#logoLink')).setAttribute('title', universeInfo);
document.querySelector('#pageContent').appendChild(Util.addDom('div', { class:'ogl_universeName', child:`${this.server.name}.${this.server.lang}` }));
this.checkPTRECompatibility();
if(this.db.serverData.serverFullID != this.server.id + this.server.lang) // reset players data after a merge
{
this.db.serverData.serverFullID = false;
/*this.ogl.db.lastStatusUpdate = 0;
this.ogl.db.lastGlobalScoreUpdate = 0;*/
this.db.lastPTREAPIUpdate = 0;
this.db.tdb = {};
this.db.pdb = {};
this.db.udb = {};
this.db.lastPinnedList = [];
this.db.quickRaidList = [];
window.location.reload();
}
}
else
{
this._fleet = new FleetManager(this);
this._empire = new EmpireManager(this);
}
this.lastUserActivity = Date.now();
this.pendingSave = false;
setInterval(() => this.scheduleSave(), 5000);
['mousemove', 'keydown', 'click', 'scroll', 'touchstart'].forEach(event =>
{
window.addEventListener(event, () => this.lastUserActivity = Date.now());
});
window.addEventListener('visibilitychange', () =>
{
if(document.visibilityState === 'hidden')
{
this.save();
}
});
window.addEventListener('beforeunload', () =>
{
this.save();
});
// save changes + allow tab sync (firefox can bug here)
/*window.addEventListener('visibilitychange', () =>
{
if(document.visibilityState === 'hidden')
{
this.save();
}
else if(document.visibilityState === 'visible')
{
setTimeout(() => this.db = this.load(), 10);
}
});*/
}
load(data)
{
data = data || GM_getValue(this.DBName) || {};
return typeof data === typeof '' ? JSON.parse(data) : data;
}
save(data)
{
if(this.page == 'empire') return;
try
{
if(data && typeof data === 'object') this.db = data;
GM_saveTab({ cache:this.cache }); // doublon for tmp fix
GM_setValue(this.DBName, JSON.stringify(this.db));
this.pendingSave = false;
}
catch(error)
{
console.log(error);
}
}
isUserActive()
{
return Date.now() - this.lastUserActivity < 10000; // 10 sec of inactivity to be inactive
}
scheduleSave()
{
if(this.isUserActive() || this.pendingSave)
{
return;
}
this.pendingSave = true;
this.save();
}
getServerData()
{
if(!this.db.serverData.galaxies || !this.db.serverData.topScore || Date.now() > this.db.lastServerUpdate + 3600000) // 1h
{
this._fetch.pending.push(
{
url:`https://${window.location.host}/api/serverData.xml`,
callback:data =>
{
let xml = new DOMParser().parseFromString(data, 'text/html');
this.db.serverData.topScore = parseInt(Number(xml.querySelector('topscore').innerText));
this.db.serverData.probeCargo = parseInt(xml.querySelector('probeCargo').innerText);
this.db.serverData.debrisFactor = parseFloat(xml.querySelector('debrisFactor').innerText) * 100;
this.db.serverData.researchSpeed = parseInt(xml.querySelector('researchDurationDivisor').innerText);
this.db.serverData.galaxies = parseInt(xml.querySelector('galaxies').innerText);
this.db.serverData.systems = parseInt(xml.querySelector('systems').innerText);
this.db.serverData.donutGalaxy = xml.querySelector('donutGalaxy').innerText == 1;
this.db.serverData.donutSystem = xml.querySelector('donutSystem').innerText == 1;
this.db.serverData.emptySystems = xml.querySelector('fleetIgnoreEmptySystems').innerText == 1;
this.db.serverData.inactiveSystems = xml.querySelector('fleetIgnoreInactiveSystems').innerText == 1;
this.db.lastServerUpdate = Date.now();
}
});
}
}
getPlanetData(reloaded)
{
if(!reloaded)
{
if(this.cache.toSend && this.mode !== 3) delete this.cache.toSend;
this.currentPlanet = {};
this.currentPlanet.dom = this._dom.planet[this.account.currentPlanetID];
const planetExist = this.db.myPlanets?.[this.account.currentPlanetID] ? true : false;
if(!this.db.noFetch)
{
if(this.page != 'fleetdispatch')
{
setTimeout(() =>
{
this._fetch.fetchMainData(false, !planetExist);
this._fetch.fetchStatus();
}, 3000);
}
}
else
{
this.db.noFetch = false;
}
this.db.myPlanets[this.account.currentPlanetID] = this.db.myPlanets[this.account.currentPlanetID] || {};
this.currentPlanet.obj = this.db.myPlanets[this.account.currentPlanetID];
this.currentPlanet.obj.type = document.querySelector('head meta[name="ogame-planet-type"]').getAttribute('content');
this.currentPlanet.obj.metal = Math.floor(resourcesBar.resources.metal?.amount || 0);
this.currentPlanet.obj.crystal = Math.floor(resourcesBar.resources.crystal?.amount || 0);
this.currentPlanet.obj.deut = Math.floor(resourcesBar.resources.deuterium?.amount || 0);
this.currentPlanet.obj.energy = Math.floor(resourcesBar.resources.energy?.amount || 0);
this.currentPlanet.obj.food = Math.floor(resourcesBar.resources.food?.amount || 0);
this.currentPlanet.obj.population = Math.floor(resourcesBar.resources.population?.amount || 0);
this.currentPlanet.obj.lifeform = document.querySelector('#lifeform .lifeform-item-icon')?.className.replace(/\D/g, '');
this.currentPlanet.obj.lastRefresh = this._time.serverTime;
['metal', 'crystal', 'deut'].forEach(resource =>
{
// update prod / sec
let prod = resourcesBar.resources[resource.replace('deut', 'deuterium')].production;
if(prod > 0) this.currentPlanet.obj[`prod${resource}`] = prod;
// update top icon storage indicator
const box = document.querySelector(`#${resource.replace('deut', 'deuterium')}_box`);
if(this.currentPlanet.obj.type == 'moon' || box.querySelector('.ogl_resourceBoxStorage')) return;
prod = prod * 3600;
const storage = this.currentPlanet.obj[`${resource}Storage`];
const timeLeft = prod > 0 ? Math.floor((storage - this.currentPlanet.obj[resource]) / prod) || 0 : Infinity;
const day = Math.max(0, Math.floor(timeLeft / 24));
const hour = Math.max(0, Math.floor(timeLeft % 24));
let text = day > 365 ? `> 365${LocalizationStrings.timeunits.short.day}` : `${day}${LocalizationStrings.timeunits.short.day} ${hour}${LocalizationStrings.timeunits.short.hour}`;
Util.addDom('div', { class:'ogl_resourceBoxStorage', child:text, parent:box });
});
}
this._dom.updateAvailable();
this._dom.updatePlanetTimers();
}
updateJQuerySettings()
{
const self = this;
$(document).on("ajaxSend", (function(event, xhr, settings)
{
if(settings.url.indexOf('page=messages&tab=') >= 0)
{
const tabID = new URLSearchParams(settings.url).get('tab');
if(tabID != 20)
{
if(self._message.spytable) self._message.spytable.classList.add('ogl_hidden');
}
}
}));
$(document).on("ajaxSuccess", function(event, xhr, settings)
{
if(settings.url.indexOf('action=getMessagesList') >= 0 && settings.data.indexOf('showTrash=true') < 0)
{
const tabID = parseInt(new URLSearchParams(settings.data).get('activeSubTab')) || -1;
self._message.tabID = tabID;
self._message.checkTab(); // check messages after pagination
}
else if(settings.url.indexOf('page=standalone') >= 0 && settings.url.indexOf('component=planetbar') >= 0)
{
self._dom.loadBase(true); // right menu reloaded
self._movement.updateSideIcons();
self.getPlanetData(true);
self._topbar.load(true);
self._ui.load(true);
self._movement.load(true);
self._topbar.checkUpgrade();
}
else if(settings.url.indexOf('action=flagArchived') >= 0)
{
let messageID = new URLSearchParams(settings.data).get('messageId') || -1;
if(self._message.messageDB?.[messageID])
{
if(xhr.responseJSON?.isArchived == 1) self._message.messageDB[messageID].isFav = true;
else self._message.messageDB[messageID].isFav = false;
self._message.saveMessagesDB();
}
}
else if(settings.url.indexOf('action=flagDeleted') >= 0)
{
let messageIDs = new URLSearchParams(settings.data.replace(/%5B%5D/g, '')).getAll('messageIds') || [-1];
messageIDs = Array.isArray(messageIDs) ? messageIDs : [messageIDs];
if(self._message.messageDB)
{
messageIDs.forEach(messageID =>
{
delete self._message.messageDB[messageID];
const spyTableLine = document.querySelector(`.ogl_spyLine[data-id="${messageID}"]`);
if(spyTableLine)
{
spyTableLine.remove();
self._message.spyRecap.count--;
self._message.spyRecap.value -= parseInt(spyTableLine.dataset.wave1);
self._message.updateSumLine();
}
if(document.querySelector(`.msg[data-msg-id="${messageID}"]`)) document.querySelector(`.msg[data-msg-id="${messageID}"]`).remove();
});
self._message.saveMessagesDB();
}
}
else if(settings.url.indexOf('action=fetchGalaxyContent') >= 0) // check galaxy on system change
{
self._galaxy.check(JSON.parse(xhr.responseText));
}
else if(settings.url.indexOf('action=checkTarget') >= 0) // fleetdispatcher fetchTargetPlayerData()
{
document.querySelector('#planetList').classList.remove('ogl_notReady');
}
else if(settings.url.indexOf('component=eventList') >= 0 && settings.url.indexOf('asJson=1') < 0)
{
const checkMovement = () =>
{
setTimeout(() => // we wait to be sure xml as been added to the DOM and OGL has been red
{
if(!self._movement)
{
checkMovement();
}
else
{
const xml = new DOMParser().parseFromString(xhr.responseText, 'text/html');
self._movement.check(xml);
self._movement.eventLoaded = true;
}
}, 50);
}
checkMovement();
}
else if(settings.url.indexOf('action=miniFleet') >= 0)
{
const json = xhr.responseJSON;
const url = new URLSearchParams(settings.data);
const mission = url.get('mission');
const galaxy = url.get('galaxy');
const system = url.get('system');
const position = url.get('position');
const type = url.get('type');
const uid = url.get('uid');
const popup = url.get('popup');
const status = json.response.success ? 'done' : 'fail';
token = json.newAjaxToken;
updateOverlayToken('phalanxSystemDialog', json.newAjaxToken);
updateOverlayToken('phalanxDialog', json.newAjaxToken);
getAjaxEventbox();
refreshFleetEvents(true);
const itemIndex = self._fleet.miniFleetQueue.findIndex(e => e.uid == uid);
const item = self._fleet.miniFleetQueue.find(e => e.uid == uid);
if(itemIndex > -1) self._fleet.miniFleetQueue.splice(itemIndex, 1);
if(status == 'fail')
{
if(item.retry < 2)
{
item.uid = crypto.randomUUID();
item.retry++;
self._fleet.miniFleetQueue.push(item);
}
else
{
self._notification.addToQueue(`[${galaxy}:${system}:${position}] ${json.response.message}`, false);
document.querySelectorAll(`[data-spy-coords="${galaxy}:${system}:${position}:${type}"]`).forEach(e => e.setAttribute('data-spy', status));
}
}
else
{
if(mission == 6 && self.db.pdb[`${galaxy}:${system}:${position}`])
{
self.db.pdb[`${galaxy}:${system}:${position}`].spy = self.db.pdb[`${galaxy}:${system}:${position}`].spy || [];
if(type == 1) self.db.pdb[`${galaxy}:${system}:${position}`].spy[0] = serverTime.getTime();
else if(type == 3) self.db.pdb[`${galaxy}:${system}:${position}`].spy[1] = serverTime.getTime();
}
document.querySelectorAll(`[data-spy-coords="${galaxy}:${system}:${position}:${type}"]`).forEach(e => e.setAttribute('data-spy', status));
/*if(json.response.slots && document.querySelector('#galaxycomponent #slotUsed'))
{
document.querySelector('#galaxycomponent #slotUsed').innerText = json.response.slots;
}
if(json.response.probes && document.querySelector('#galaxycomponent #probeValue'))
{
document.querySelector('#galaxycomponent #probeValue').innerText = json.response.probes;
}*/
//addToTable(json.response.message, "success", json.response.shipsSent);
$("#slotUsed").html(tsdpkt(json.response.slots));
setShips("probeValue", tsdpkt(json.response.probes));
setShips("recyclerValue", tsdpkt(json.response.recyclers));
setShips("missileValue", tsdpkt(json.response.missiles));
}
if(popup && mission != 6)
{
if (json.response.success)
{
fadeBox(json.response.message + ' ' + json.response.coordinates.galaxy + ":" + json.response.coordinates.system + ":" + json.response.coordinates.position, !json.response.success);
}
else
{
fadeBox(json.response.message, true);
}
}
if(self._fleet.miniFleetQueue.length > 0)
{
setTimeout(() => self._fleet.sendNextMiniFleet(), 500)
}
}
else if(settings.url.indexOf('page=highscoreContent') >= 0)
{
self._highscore.check();
}
else if(settings.url.indexOf('action=reCommission') >= 0)
{
window.stop();
/*window.stop();
self.currentPlanet.obj.wreckfield = false;
ogl.save();
window.location.reload();*/
}
else if(settings.url.indexOf('action=startRepairs') >= 0)
{
window.stop();
/*window.stop();
const stats = self._stats.getDayStats(self._time.timeToKey(serverTime.getTime()));
const shipsToRepair = document.querySelectorAll('.repairableShips .ships');
const debugObj = {};
debugObj.key = self._time.timeToKey(serverTime.getTime());
debugObj.ships = {};
shipsToRepair.forEach(item =>
{
const ship = {};
ship.id = parseInt(item.id.replace(/\D/g, '') || 0);
ship.amount = parseInt(item.querySelector('.level')?.innerText?.replace(/\D/g, '') || 0);
debugObj.ships[ship.id] = ship;
stats.raid = stats.raid || {};
stats.raid.gain = stats.raid.gain || {};
stats.raid.gain[ship.id] = (stats.raid.gain[ship.id] || 0) + ship.amount;
});
self.currentPlanet.obj.wreckfield = 9999999999999;
self.db.debugData = self.db.debugData || [];
self.db.debugData.push(debugObj);
ogl.save();
window.location.reload();*/
}
else if(settings.url.indexOf('component=repairlayer') >= 0)
{
initTooltips();
}
else if(settings.url.indexOf('action=getDetails') >= 0)
{
document.querySelectorAll('#technologydetails').forEach((e, index) => { if(index > 0) e.remove(); });
}
else if(settings.url.indexOf('component=messagedetails') >= 0 && settings.url.indexOf('messageId') >= 0)
{
self._message.checkDialog();
}
else if(settings.url.indexOf('action=sendDiscoveryFleet') >= 0 || settings.url.indexOf('action=sendSystemDiscoveryFleet') >= 0)
{
const result = xhr?.responseJSON?.response;
if(result && result.success)
{
if(result.coordinates)
{
self.db.lastDiscovery = `${result.coordinates.galaxy}:${result.coordinates.system}`;
}
else
{
self.db.lastDiscovery = `${result.sentToCoordinates[0].galaxy}:${result.sentToCoordinates[0].system}`;
}
self.save();
}
}
});
$.ajaxSetup(
{
beforeSend:function(xhr, settings)
{
if(this.url.indexOf('action=checkTarget') >= 0 && !self?._fleet?.firstLoadCancelled) // clear default fleet loading
{
if(window.fleetDispatcher)
{
fleetDispatcher.fetchTargetPlayerDataTimeout = null;
self._fleet.firstLoadCancelled = true;
xhr.abort();
}
}
else if(this.url.indexOf('action=fetchGalaxyContent') >= 0) // abort galaxy spam
{
if(self._galaxy.xhr) self._galaxy.xhr.abort();
self._galaxy.xhr = xhr;
}
else if(this.url.indexOf('action=getMessagesList') >= 0) // abort message spam
{
if(self._message.xhr) self._message.xhr.abort();
self._message.xhr = xhr;
if(settings.data.indexOf('activeSubTab=20') > -1 && settings.data.indexOf('showTrash=false') > -1)
{
self._message.loadSpyTable(true);
}
}
}
});
}
checkPTRECompatibility()
{
if(serverTime.getTime() > this.id[1] + 86400000)
{
let json =
{
ogl_id:this.id[0] || '-',
version:this.version || '-',
script_name:GM_info.script.name || '-',
script_namespace:GM_info.script.downloadURL || '-',
}
this.PTRE.postPTRECompatibility(json);
}
}
createPlayer(id)
{
this.db.udb[id] = { uid:parseInt(id) };
return this.db.udb[id];
}
removeOldPlanetOwner(coords, newUid)
{
Object.values(this.db.udb).filter(e => e.planets?.indexOf(coords) > -1).forEach(old =>
{
if(old.uid != newUid)
{
// remove the planet from the old user list
const index = this.db.udb[old.uid].planets.indexOf(coords);
this.db.udb[old.uid].planets.splice(index, 1);
// delete the old user if the planet list is empty
if(this.db.udb[old.uid].planets.length < 1) delete this.db.udb[old.uid];
if(this.db.udb[old.uid] && document.querySelector('.ogl_side.ogl_active') && this.db.currentSide == old.uid)
{
if(document.querySelector('.ogl_side.ogl_active') && this.db.currentSide == old.uid) this._topbar.openPinnedDetail(old.uid);
}
}
});
}
importData(importButton, dataType)
{
const file = importButton.files[0];
const reader = new FileReader();
reader.onload = () =>
{
this._popup.open(Util.addDom('div', { child:'<div>Importing data, please wait...</div><hr><div class="ogl_loading"></div>' }));
let imported;
let error;
try { imported = JSON.parse(reader.result); }
catch (e) { error = 'cannot read file'; }
if(!error && imported && imported.dataFormat > 10)
{
if(dataType == 'all')
{
const stats = JSON.parse(JSON.stringify(this.db.stats));
this.db = imported;
for(const date in stats)
{
if(!this.db.stats.hasOwnProperty(date))
{
this.db.stats[date] = stats[date];
}
}
}
else if(dataType == 'stats')
{
for(const date in imported.stats)
{
if(!this.db.stats.hasOwnProperty(date))
{
this.db.stats[date] = imported.stats[date];
}
}
}
document.location.reload();
}
else
{
this._popup.close();
this._notification.addToQueue(`Error, ${error||"wrong data format"}`, false);
}
}
if(file) reader.readAsText(file);
}
checkDataFormat()
{
if(this.db.dataFormat < 10) // fix v4 data
{
let legacyDBName = `ogl_test_${this.server.id}-${this.server.lang}_${this.account.id}`;
let legacyDB = JSON.parse(GM_getValue(legacyDBName) || '{}');
if(legacyDB.pinnedList?.length > 0 || legacyDB.positions?.length > 0)
{
if(confirm('Do you want to import v4 pinned targets ?'))
{
this._popup.open(Util.addDom('div', { child:'<div>importing v4 targets, please wait...</div><hr><div class="ogl_loading"></div>' }));
// add v4 pinned players
legacyDB.pinnedList.forEach(id =>
{
this.db.lastPinnedList = Array.from(new Set([id, ...this.db.lastPinnedList]));
});
if(this.db.lastPinnedList.length > 30) this.db.lastPinnedList.length = 30;
// add v4 tagged planets
legacyDB.positions.filter(position => position.color).forEach(position =>
{
this.db.tdb[position.rawCoords] = { tag:position.color.replace('half', '') };
});
this.db.dataFormat = 10;
this._popup.close();
window.location.reload();
}
else
{
this.db.dataFormat = 10;
}
}
else
{
this.db.dataFormat = 10;
}
}
if(this.db.dataFormat < 12) // fix beta todolist
{
document.querySelectorAll('.planetlink, .moonlink').forEach(planet =>
{
const urlParams = new URLSearchParams(planet.getAttribute('href'));
const id = urlParams.get('cp').split('#')[0];
if(this.db.myPlanets[id]) delete this.db.myPlanets[id].todolist;
});
if(this.cache) delete this.cache.toSend;
this.db.dataFormat = 12;
}
if(this.db.dataFormat < 14) // fix beta stats
{
this.db.initialTime = Date.now();
this.db.stats = {};
this.cache.raid = {};
this.db.dataFormat = 14;
}
if(this.db.dataFormat < 15) // fix beta stats
{
Object.entries(this.db.stats || {}).forEach(entry =>
{
if(entry[0].indexOf('-') > -1) return;
const midnight = parseInt(entry[0]);
const value = entry[1];
const date = new Date(midnight);
const key = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
if(!this.db.stats[key])
{
this.db.stats[key] = value;
delete this.db.stats[midnight];
}
});
this.db.dataFormat = 15;
}
if(this.db.dataFormat < 16) // fix beta stats
{
Object.entries(this.db.stats || {}).forEach(entry =>
{
const oldKey = entry[0].split('-');
let newMonth = parseInt(oldKey[1]) + 1;
let newYear = parseInt(oldKey[0]);
if(newMonth > 12)
{
newMonth = 1;
newYear++;
}
const value = entry[1];
const key = `${newYear}-${newMonth}-${oldKey[2]}`;
delete this.db.stats[oldKey.join('-')];
this.db.stats[key] = value;
});
this.db.dataFormat = 16;
}
if(this.db.dataFormat < 17) // fix msu
{
this.db.options.msu = '3:2:1';
this.db.dataFormat = 17;
}
}
calcExpeditionMax()
{
const threshold =
[
{ topScore:10000, base:10, max:40000 },
{ topScore:100000, base:125, max:500000 },
{ topScore:1000000, base:300, max:1200000 },
{ topScore:5000000, base:450, max:1800000 },
{ topScore:25000000, base:600, max:2400000 },
{ topScore:50000000, base:750, max:3000000 },
{ topScore:75000000, base:900, max:3600000 },
{ topScore:100000000, base:1050, max:4200000 },
{ topScore:Infinity, base:1250, max:5000000 },
].find(e => e.topScore >= this.db.serverData.topScore);
let itemBoost = 1;
const bonusItems =
{
"83e5d5b5e3e6ba16eb73edd6731a25ed1feff8a1":0.1,
"f2f1bf68ded681adf6b45b24a8084b3861a5ce94":0.15,
"d831a85f8f53defc3e51b7551401b21fb98c28ad":0.2,
"fd38bf4fa0e07377c2a18556424eee14a6700654":0.25,
"7e05baae79bde905f5b2c89bb881d7ff04e8fa73":0.3,
"23c859c9f8b4ea7c562719ac829bfc9799250b33":0.35,
"a5ab323cadd8c172957451f8ddd9950f1c101966":0.4
}
this.db.activeItems.forEach(item =>
{
if(bonusItems[item]) itemBoost += bonusItems[item];
});
const base = (this.account.class == 3 ? threshold.max * 3 * this.server.economySpeed : threshold.max * 2);
let maxResources =
base *
(1+(this.db.lfBonuses?.Characterclasses3?.bonus||0)/100) *
(1+(this.db.lfBonuses?.ResourcesExpedition?.bonus||0)/100) *
itemBoost;
if(this.db.options.expeditionValue)
{
if(this.db.options.expeditionValue.toString().indexOf('%') >= 1) // percent mode
{
maxResources = Math.ceil(maxResources * this.db.options.expeditionValue.replace(/\D/g, '') / 100);
}
else // value mode
{
maxResources = this.db.options.expeditionValue;
}
}
return { max:Math.round(maxResources), threshold:threshold };
}
loadPlanetList()
{
this.account.planets = [];
this.account.planetsIDs = [];
document.querySelectorAll('.smallplanet').forEach(line =>
{
const planet = {};
planet.id = new URLSearchParams(line.querySelector('.planetlink')?.getAttribute('href'))?.get('cp')?.split('#')?.[0] || -1;
planet.moonID = new URLSearchParams(line.querySelector('.moonlink')?.getAttribute('href'))?.get('cp')?.split('#')?.[0] || -1;
planet.coords = line.querySelector('.planet-koords').textContent.slice(1, -1);
planet.isCurrent = line.classList.contains('hightlightPlanet') || line.classList.contains('hightlightMoon');
planet.currentType = planet.isCurrent && line.classList.contains('hightlightPlanet') ? 'planet' : planet.isCurrent && line.classList.contains('hightlightMoon') ? 'moon' : false;
this.account.planets.push(planet);
if(planet.id > -1) this.account.planetsIDs.push(planet.id);
if(planet.moonID > -1) this.account.planetsIDs.push(planet.moonID);
});
this.account.planets.getNext = offset => Util.reorderArray(this.account.planets, this.account.planets.findIndex(e => e.isCurrent))?.[(offset||0)+1] || this.account.planets[0];;
this.account.planets.getNextWithMoon = offset => Util.reorderArray(this.account.planets.filter(e => e.moonID > -1), this.account.planets.filter(e => e.moonID > -1).findIndex(e => e.isCurrent))?.[(offset||0)+1] || this.account.planets[0];;
this.account.planets.getPrev = offset => Util.reorderArray(this.account.planets, this.account.planets.findIndex(e => e.isCurrent), true)?.[offset||0] || this.account.planets[0];;
this.account.planets.getPrevWithMoon = offset => Util.reorderArray(this.account.planets.filter(e => e.moonID > -1), this.account.planets.filter(e => e.moonID > -1).findIndex(e => e.isCurrent), true)?.[offset||0] || this.account.planets[0];;
this.account.planets.getCurrent = () => this.account.planets.find(e => e.isCurrent) || this.account.planets[0];
this.account.planets.getByCoords = coords => this.account.planets.find(e => coords == e.coords);
// remove old planets
Object.keys(this.db.myPlanets).forEach(dbPlanetID =>
{
if(this.account.planetsIDs.indexOf(dbPlanetID) < 0) delete(this.db.myPlanets[dbPlanetID]);
});
}
}
GM_getTab(params => unsafeWindow.ogl = new OGLight(params));
class Manager
{
constructor(ogl)
{
this.ogl = ogl;
this.ogl['_'+this.constructor.name.toLowerCase().replace('manager', '')] = this;
if(this.load) this.load();
}
}
class DomManager extends Manager
{
load()
{
this.loadBase();
this.loadFleet();
this.updateRecap();
this.updateLeftMenu();
this.updateFooter();
this.updateTop();
}
redraw(element, fragment, callback)
{
requestAnimationFrame(() =>
{
if(callback) callback();
element.innerText = '';
element.appendChild(fragment);
});
}
loadBase(reload)
{
this.planet = {};
this.planetList = document.querySelector('#planetList');
this.smallplanet = document.querySelectorAll('.smallplanet');
this.links = document.querySelector('#links');
this.leftMenu = document.querySelector('#menuTable');
this.footer = document.querySelector('#siteFooter .fright');
this.mainClock = document.querySelector('#bar .OGameClock');
this.countColonies = document.querySelector('#countColonies');
if(!this.ogl.db.options.displayPlanetTimers)
{
this.planetList.classList.add('ogl_alt');
}
this.smallplanet.forEach(line =>
{
const planet = line.querySelector('.planetlink');
const moon = line.querySelector('.moonlink');
const planetID = new URLSearchParams(line.querySelector('.planetlink')?.getAttribute('href'))?.get('cp')?.split('#')?.[0] || -1;
const moonID = new URLSearchParams(line.querySelector('.moonlink')?.getAttribute('href'))?.get('cp')?.split('#')?.[0] || -1;
planet._ogl = {};
planet._ogl.type = 'planet';
planet._ogl.id = planetID;
planet._ogl.relatedID = moonID;
planet._ogl.moonLink = moon;
planet._ogl.resources = Util.addDom('div', { class:'ogl_available', parent:planet });
planet._ogl.timer = Util.addDom('div', { class:'ogl_refreshTimer ogl_planet', parent:planet.parentElement });
planet._ogl.queue = Util.addDom('div', { class:'ogl_buildIconList', parent:planet });
planet._ogl.coords = planet.querySelector('.planet-koords').textContent.slice(1, -1);
planet._ogl.name = planet.querySelector('.planet-name').textContent;
planet._ogl.sideIcon = Util.addDom('div', { class:'ogl_sideIconTop', parent:line });
planet._ogl.sideIconBack = Util.addDom('div', { class:'ogl_sideIconBottom', parent:line });
planet._ogl.sideInfo = Util.addDom('div', { class:'ogl_sideIconInfo', parent:line });
this.planet[planetID] = planet;
if(moon)
{
moon._ogl = {};
moon._ogl.type = 'moon';
moon._ogl.id = moonID;
moon._ogl.relatedID = planetID;
moon._ogl.planetLink = planet;
moon._ogl.resources = Util.addDom('div', { class:'ogl_available', parent:moon });
moon._ogl.timer = Util.addDom('div', { class:'ogl_refreshTimer ogl_moon', parent:moon.parentElement });
moon._ogl.queue = Util.addDom('div', { class:'ogl_buildIconList', parent:moon });
moon._ogl.jumpgateLevel = moon.getAttribute('data-jumpgatelevel');
moon._ogl.coords = planet.querySelector('.planet-koords').innerText.slice(1, -1);
moon._ogl.sideIcon = planet._ogl.sideIconBack;
moon._ogl.sideInfo = planet._ogl.sideInfo;
this.planet[moonID] = moon;
}
});
this.recap = Util.addDom('div', { class:'ogl_recap', parent:this.planetList });
if(reload) return;
this.miniStats = Util.addDom('div', { class:'ogl_miniStats ogl_ogameDiv', parent:this.links, onclick:() => { this.ogl._stats.showDetails(); }});
const LFComponent = document.querySelector('#commandercomponent #lifeform');
if(LFComponent) Util.addDom('a', { child:'genetics', href:`https://${window.location.host}/game/index.php?page=ingame&component=lfbonuses`, class:'ogl_lfBonusesLink tooltip', title:'Lifeforms Bonuses', parent:LFComponent });
}
loadFleet()
{
if(this.ogl.page !== 'fleetdispatch') return;
this.fleet1 = document.querySelector('#fleet1');
this.fleet2 = document.querySelector('#fleet2');
this.sendAll = document.querySelector('#sendall');
this.resetAll = document.querySelector('#resetall');
this.secondCol = document.querySelector('.secondcol');
this.warning = this.fleet1.querySelector('#warning');
this.component = document.querySelector('#fleetdispatchcomponent');
this.fleetResources = document.querySelectorAll('#fleet2 .resourceIcon');
this.requiredShips = Util.addDom('span', { class:'ogl_requiredShips', parent:document.querySelector("#civilships #civil") || this.warning });
this.technology = document.querySelectorAll('[data-technology]');
this.tech = {};
this.technology.forEach(tech =>
{
tech._ogl = {};
tech._ogl.id = parseInt(tech.getAttribute('data-technology'));
tech._ogl.shipFlag = Util.addDom('div', { class:'ogl_shipFlag', parent:tech });
tech._ogl.input = tech.querySelector('input');
tech._ogl.amount = tech.querySelector('.amount');
tech._ogl.reverse = Util.addDom('div', { class:'ogl_reverse material-icons tooltip', title:'Invert selection', child:'contrast', parent:tech._ogl.shipFlag, onclick:e =>
{
e.stopPropagation();
this.ogl._fleet.reverseShip(tech._ogl.id);
}});
if(this.ogl.fretShips.indexOf(tech._ogl.id) > -1)
{
const favClass = tech._ogl.id == this.ogl.db.options.defaultShip ? 'material-icons ogl_fav tooltip' : 'material-icons ogl_fav tooltip ogl_grayed';
const lockClass = tech._ogl.id == this.ogl.db.keepEnoughCapacityShip ? 'material-icons ogl_shipLock tooltip' : 'material-icons ogl_shipLock tooltip ogl_grayed';
tech._ogl.fav = Util.addDom('div', { class:favClass, title:'Default ship', child:'star', parent:tech._ogl.shipFlag, onclick:e =>
{
e.stopPropagation();
this.ogl._fleet.favShip(tech._ogl.id);
}});
if([202, 203, 219, 200].indexOf(tech._ogl.id) > -1)
{
tech._ogl.lock = Util.addDom('div', { class:lockClass, title:'Locked ship', child:'blocked', parent:tech._ogl.shipFlag, onclick:e =>
{
e.stopPropagation();
this.ogl._fleet.lockShip(tech._ogl.id);
}});
}
}
this.tech[tech._ogl.id] = tech;
});
this.fleetResources.forEach(resourceIcon =>
{
Util.addDom('div', { class:'ogl_reverse material-icons', child:'contrast', parent:resourceIcon, onclick:() =>
{
this.ogl._fleet.reverseResources(resourceIcon);
}});
});
}
updateRecap(data)
{
const fragment = document.createDocumentFragment();
['metal', 'crystal', 'deut', 'msu'].forEach(resource =>
{
const line = Util.addDom('div', { class:`ogl_icon ogl_${resource}`, parent:fragment });
Util.addDom('span', { parent:line, child:Util.formatToUnits(data?.total?.[resource] || 0) });
Util.addDom('span', { parent:line, child:'+'+Util.formatToUnits(Math.floor(data?.prod?.[resource] || 0, 1)) });
});
this.redraw(this.recap, fragment);
}
updateLeftMenu()
{
const version = oglVersion;
const fragment = document.createDocumentFragment();
const oglBlock = Util.addDom('li', { parent:fragment });
Util.addDom('span', { parent:oglBlock, class:'menu_icon ogl_leftMenuIcon', child:`<a class="tooltipRight" href="https://greasyfork.org/fr/scripts/514909-oglight" target="_blank"><i class="material-icons">oglight_simple</i></a>` });
Util.addDom('a', { parent:oglBlock, class:'menubutton tooltipRight', href:'https://board.fr.ogame.gameforge.com/index.php?thread/722955-oglight/', target:'_blank', child:`<span class="textlabel">OGLight ${version}</span>` });
if(this.ogl.ptreKey)
{
const ptreBlock = Util.addDom('li', { parent:fragment });
Util.addDom('span', { parent:ptreBlock, class:'menu_icon ogl_leftMenuIcon ogl_ptreActionIcon', child:`<a class="tooltipRight" title="PTRE last request status" href="#"><i class="material-icons">sync_alt</i></a>`, onclick:() => this.ogl.PTRE.displayLogs() });
Util.addDom('a', { parent:ptreBlock, class:'menubutton tooltipRight', href:'https://ptre.chez.gg/', target:'_blank', child:`<span class="textlabel">PTRE</span>` });
}
this.leftMenu.appendChild(fragment);
}
updateFooter()
{
const lang = ['fr', 'de', 'en', 'es', 'pl', 'it', 'ru', 'ar', 'mx', 'tr', 'fi', 'tw', 'gr', 'br', 'nl',
'hr', 'sk', 'cz', 'ro', 'us', 'pt', 'dk', 'no', 'se', 'si', 'hu', 'jp', 'ba'].indexOf(this.ogl.server.lang);
this.footer.innerHTML +=
`
| <a target="_blank" href="https://www.mmorpg-stat.eu/0_fiche_joueur.php?pays=${lang}&ftr=${this.ogl.account.id}.dat&univers=_${this.ogl.server.id}">Mmorpg-stat</a>
| <a target="_blank" href="https://ogotcha.oplanet.eu/${this.ogl.server.lang}">Ogotcha</a>
| <a>OGL ${this.ogl.version}</a>
`;
}
updateTop()
{
// ping
this.ping = Util.addDom('div', { class:'ogl_ping', parent:document.querySelector('#bar') });
this.updatePing();
// LF top icon
if(this.ogl.db?.myPlanets && this.ogl.db?.lfBonuses)
{
const currentLF = `lifeform${this.ogl.db.myPlanets[this.ogl.account.currentPlanetID]?.lifeform || 0}`;
const iconLF = document.querySelector('#lifeform .lifeform-item-icon');
if(iconLF) iconLF.innerHTML = `<span>${(this.ogl.db.lfBonuses[currentLF]?.bonus || 0) * 10}</span>`;
}
// wreckfield top icon
const wreckfield = document.querySelector('#attack_alert.wreckField a');
if(wreckfield)
{
wreckfield.setAttribute('href', `https://${window.location.host}/game/index.php?page=ingame&component=facilities&openTech=36`);
wreckfield.classList.remove('overlay');
}
}
updatePing()
{
if(performance.getEntriesByType)
{
const navigation = performance.getEntriesByType('navigation')[0];
this.pageLoadingTime = navigation.domContentLoadedEventEnd - navigation.fetchStart;
this.ping.innerText = `${Util.formatNumber(Math.round(Math.max(this.pageLoadingTime, 0)))} ms`;
if(this.pageLoadingTime > 1000) this.ping.className = 'ogl_ping ogl_danger';
else if(this.pageLoadingTime > 700) this.ping.className = 'ogl_ping ogl_warning';
else this.ping.className = 'ogl_ping ogl_ok';
}
}
updateMiniStats(data)
{
const fragment = document.createDocumentFragment();
Util.addDom('h3', { class:'ogl_header', child:data.title, parent:fragment });
let content = Util.addDom('div', { parent:fragment });
['metal', 'crystal', 'deut', 'dm', 'artefact', 'msu'].forEach(type =>
{
Util.addDom('div', {class:`ogl_icon ogl_${type}`, parent:content, child:`<span>${Util.formatToUnits(data[type], 1, true)}</span>`});
});
this.redraw(this.miniStats, fragment);
}
updateAvailable()
{
Object.values(this.ogl._dom.planet).forEach(planet =>
{
const id = planet._ogl.id;
const div = planet._ogl.resources;
const fragment = document.createDocumentFragment();
this.ogl.db.myPlanets[id] = this.ogl.db.myPlanets[id] || {};
['metal', 'crystal', 'deut'].forEach(resourceName =>
{
const resource = this.ogl.db.myPlanets[id]?.[resourceName] || 0;
const storage = this.ogl.db.myPlanets[id]?.[resourceName+'Storage'] || 0;
const span = Util.addDom('span', { class:'ogl_'+resourceName, parent:fragment, child:Util.formatToUnits(resource, 1) });
if(resource >= storage && planet._ogl.type == 'planet') span.classList.add('ogl_danger');
else if(resource >= storage * .9 && planet._ogl.type == 'planet') span.classList.add('ogl_warning');
else
{
span.classList.remove('ogl_warning');
span.classList.remove('ogl_danger');
}
});
this.ogl._dom.redraw(div, fragment, () =>
{
if(!planet.classList.contains('tooltipLeft'))
{
if(planet._ogl.type == 'planet')
{
planet.classList.add('tooltipLeft');
planet.classList.remove('tooltipRight');
planet.querySelector('.planet-koords').innerHTML = `<span class="ogl_hidden">[</span>${planet._ogl.coords}<span class="ogl_hidden">]</span>`;
}
else
{
planet.classList.add('tooltipRight');
planet.classList.remove('tooltipLeft');
}
if(this.ogl.db.myPlanets[id]?.wreckfield && !planet.querySelector('.wreckFieldIcon'))
{
const icon = Util.addDom('a', { class:'wreckFieldIcon tooltip js_hideTipOnMobile ogl_active ogl_wreckfieldIcon', parent:planet.parentNode, href:`https://${window.location.host}/game/index.php?page=ingame&component=facilities&cp=${id}&openTech=36`, child:'<span class="icon icon_wreck_field"></span>' });
if(serverTime.getTime() >= this.ogl.db.myPlanets[id].wreckfield) icon.classList.add('ogl_ok');
}
}
});
});
}
updatePlanetTimers()
{
Object.values(this.planet).forEach(planet =>
{
const id = planet._ogl.id;
const timerDom = planet._ogl.timer;
if(!timerDom) return;
let timerValue = serverTime.getTime() - (this.ogl.db.myPlanets[id]?.lastRefresh || 1);
timerValue = Math.min(Math.floor(timerValue / 60000), 60);
const timerColor = timerValue > 30 ? '#ef7676' : timerValue >= 15 ? '#e3bb28' : '#38c56e';
requestAnimationFrame(() =>
{
timerDom.style.color = timerColor;
timerDom.innerText = timerValue.toString();
});
});
if(!this.planetTimerInterval)
{
this.planetTimerInterval = setInterval(() => this.ogl._dom.updatePlanetTimers(), 60000);
}
}
}
class LangManager extends Manager
{
load()
{
this.raw =
{
metal:'Metal',
crystal:'Crystal',
deut:'Deuterium',
artefact:'Artefact',
dm:'Dark Matter',
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',
216:'Trade Ship',
217:'Crawler',
218:'Reaper',
219:'Pathfinder',
220:'Trade Ship',
}
this.en =
{
ship:"Ships",
item:"Item",
other:"Other",
resource:"Resources",
battle:"Battle",
blackhole:"Black hole",
early:"Early",
late:"Late",
trader:"Trader",
nothing:"Nothing",
pirate:"Pirates",
alien:"Aliens",
duration:"Duration",
defaultShip:"Default ship type",
defaultMission:"Default mission type",
useClientTime:"Use client time",
displayMiniStats:"Stats range",
displaySpyTable:"Display spy table",
spyTableRules:"Spy table rules",
displayPlanetTimers:"Display planets timer",
disablePlanetTooltips:"Disable planets menu tooltips",
showMenuResources:"Planets menu layout",
reduceLargeImages:"Fold large images",
ignoreExpeShips:"Ignore ships found in expeditions",
ignoreExpeShipsLoss:"Ignore ships lost in expeditions",
ignoreConsumption:"Ignore fleet consumption",
resourceTreshold:"Resource threshold",
tooltipDelay:"Tooltip delay (ms)",
galaxyUp:"Next galaxy",
galaxyDown:"Previous galaxy",
galaxyLeft:"Previous system",
galaxyRight:"Next system",
previousPlanet:"Previous planet",
nextPlanet:"Next planet",
nextPinnedPosition:"Next pinned position",
fleetRepeat:"Repeat last fleet",
fleetSelectAll:"<div>Select all ships (fleet1)<hr>Select all resources (fleet2)</div>",
expeditionSC:'Small cargo expedition',
expeditionLC:'Large cargo expedition',
expeditionPF:'Pathfinder expedition',
galaxySpySystem:"System spy",
collectLinked:"Collect to linked planet/moon",
keyboardActions:"Keyboard settings",
enableNotifications:"Enable notifications",
expeditionValue:"Expedition value",
expeditionValueTT:"<ul><li>The custom value aimed by your expeditions</li><li>Set it to <b>0</b> to use the default calculated value</li><li>You can use <b>%</b> to aim a percent of the calculated value</li></ul>",
expeditionBigShips:"Allowed biggest ships",
expeditionRandomSystem:"Random system",
expeditionShipRatio:"Ships found value (%)",
fleetLimiter:"Fleet limiter",
fleetLimiterTT:"Chose the amount of ships / resources to keep on your planets",
menu:"Toggle OGLight menu",
quickRaid:"Quick raid",
attackNext:"Attack next planet",
autoCleanReports:"Auto clean reports",
autoCleanCounterSpies:"Auto clean counter spies",
noCurrentPin:"Error, no target pinned",
backFirstFleet:"Back first fleet",
backLastFleet:"Back last fleet sent",
fleetReverseAll:"Invert selection",
fleetResourcesSplit:"Split ships/resources",
manageData:"Manage OGLight data",
profileButton:"Limiters settings",
limiters:"Limiters",
expeditionRedirect:"Redirect to the next planet/moon",
playerProfile:"Player profile",
topReportDetails:"Top report details",
reportFound:"Top report",
discovery:"Send a discovery",
collectResources:"Collect resources",
accountSummary:"Account summary",
stats:"Stats",
taggedPlanets:"Tagged planets",
pinnedPlayers:"Pinned players",
oglSettings:"OGLight settings",
coffee:"Buy me a coffee",
syncEmpire:"Sync empire data",
repeatQueue:"Repeat the amount above in a new queue X time.<br>This operation can take a while",
spyPlanet:"Spy this planet",
spyMoon:"Spy this moon",
resourceLimiter:"Substract the amount of resources defined in your profile limiter",
fleetLimiter:"Substract the amount of ships defined in your profile limiter",
forceKeepCapacity:"Keep enough capacity on you planet to move your resources (has priority over limiters)",
forceIgnoreFood:"Ignore food (has priority over limiters)",
resetStats:"Reset stats",
resetTaggedPlanets:"Reset tagged planets",
resetPinnedPlayers:"Reset pinned players",
resetAll:"Reset all data",
resetStatsLong:"Do you really want to reset OGLight stats data ?",
resetTaggedPlanetsLong:"Do you really want to reset OGLight tagged planets data ?",
resetPinnedPlayersLong:"Do you really want to reset OGLight pinned players data ?",
resetAllLong:"Do you really want to reset all OGLight data ?",
reportBlackhole:"Report a black hole",
reportBlackholeLong:"Do you really want to add this black hole ?",
emptyPlayerList:"There is no player in this list",
debugMode:"Debug mode",
sim:"Battle sim",
converter:"Battle converter",
siblingPlanetMoon:"Sibling planet / moon",
oglMessageDone:"This message has been read by OGLight",
ptreMessageDone:"activity sent to PTRE",
boardTab:"Display board news",
msu:"Metal standard unit",
notifyNoProbe:"Feature disabled :(",
shortcutsOnRight:"Display shortcuts under the planet menu",
ptreTeamKey:"Team key",
ptreLogs:"Display PTRE errors",
ptreActivityImported:"activity imported to PTRE",
ptreActivityAlreadyImported:"activity already imported to PTRE",
ptreSyncTarget:"Sync with PTRE",
ptreManageTarget:"Manage on PTRE",
colorblindMode:"Colorblind mode",
fleetQuickCollect:"Quick collect this planet resources",
sidePanelOnLeft:"Side panel on left",
galaxyReload:"Reload galaxy",
spyTableMSU:"Use MSU in the spy table",
};
this.fr =
{
ship:"Vaisseaux",
item:"Item",
other:"Autre",
resource:"Ressources",
battle:"Combat",
blackhole:"Trou noir",
early:"Avance",
late:"Retard",
trader:"Marchand",
nothing:"Rien",
pirate:"Pirates",
alien:"Aliens",
duration:"Durée",
defaultShip:"Vaisseau par défaut",
defaultMission:"Mission par défaut",
useClientTime:"Utiliser l'heure du client",
displayMiniStats:"Fourchette",
displaySpyTable:"Afficher le tableau d'espio",
spyTableRules:"Règles du tableau d'espio",
displayPlanetTimers:"Afficher les timers des planètes",
disablePlanetTooltips:"Cacher les tooltips du menu des planètes",
showMenuResources:"Affichage du menu des planètes",
reduceLargeImages:"Réduire les grandes images",
ignoreExpeShips:"Ignorer les vaisseaux trouvés en expédition",
ignoreExpeShipsLoss:"Ignorer les vaisseaux perdus en expédition",
ignoreConsumption:"Ignorer la consommation des flottes",
resourceTreshold:"Seuil de ressources",
tooltipDelay:"Délai des tooltips (ms)",
galaxyUp:"Galaxie suivante",
galaxyDown:"Galaxie précédente",
galaxyLeft:"Système précédent",
galaxyRight:"Système suivant",
previousPlanet:"Planète précédente",
nextPlanet:"Planète suivante",
nextPinnedPosition:"Position épinglée suivante",
fleetRepeat:"Répéter la dernière flotte",
fleetSelectAll:"<div>Selectionner tous les vaisseaux (fleet1)<hr>Selectionner toutes les ressources (fleet2)</div>",
expeditionSC:"Expédition au petit transporteur",
expeditionLC:"Expédition au grand transporteur",
expeditionPF:"Expédition à l'éclaireur",
galaxySpySystem:"Espionnage du système",
collectLinked:"Rapatrier vers les planètes/lunes liée",
keyboardActions:"Raccourcis clavier",
enableNotifications:"Activer les notifications",
expeditionValue:"Valeur max. expédition",
expeditionValueTT:"<ul><li>La valeur visée par les expédition</li><li>Laisser à <b>0</b> pour utiliser la valeur calculée par OGLight</li><li>Vous pouvez mettre une valeur fixe pour viser un montant précis</li><li>Vous pouvez utiliser <b>%</b> pour viser un pourcentage de la valeur calculée</li><ul>",
expeditionBigShips:"Gros vaisseaux autorisés",
expeditionRandomSystem:"Système aléatoire",
expeditionShipRatio:"Valeur vaisseaux trouvés (%)",
fleetLimiter:"Limiteur de flotte",
fleetLimiterTT:"Choisir le nombre de vaisseau et la quantité de ressources à garder sur les planètes/lunes",
menu:"Afficher/masquer le menu OGLight",
quickRaid:"Raid rapide",
attackNext:"Attaquer la planète suivante",
autoCleanReports:"Nettoyage automatique des rapports",
autoCleanCounterSpies:"Nettoyage automatique des contre-espio",
noCurrentPin:"Pas de cible épinglée actuellement",
backFirstFleet:"Rappeler la prochaine flotte",
backLastFleet:"Rappeler la dernière flotte envoyée",
fleetReverseAll:"Inverser la sélection",
fleetResourcesSplit:"Diviser les vaisseaux/ressources",
manageData:"Gestion des données OGLight",
profileButton:"Configuration des limiteurs",
limiters:"Limiteurs",
expeditionRedirect:"Rediriger vers la planète/lune suivante",
playerProfile:"Profil du joueur",
topReportDetails:"Détails du meilleur rapport",
reportFound:"Meilleur rapport",
discovery:"Envoyer une exploration",
collectResources:"Rapatrier les ressources",
accountSummary:"Résumé du compte",
stats:"Statistiques",
taggedPlanets:"Planètes marquées",
pinnedPlayers:"Joueurs épinglés",
oglSettings:"Configuration d'OGLight",
coffee:"Buy me a coffee",
syncEmpire:"Synchroniser les données de l'empire",
repeatQueue:"Répéter le nombre ci-dessus dans une nouvelle file X fois.<br>Cette opération peut prendre un moment",
spyPlanet:"Espionner cette planète",
spyMoon:"Espionner cette lune",
resourceLimiter:"Soustraire le montant de ressources indiqué dans le limiteur",
fleetLimiter:"Soustraire le nombre de vaisseaux indiqué dans le limiteur",
forceKeepCapacity:"Garder assez de capacité sur la planète pour bouger les ressources (a la priorité sur le limiteur)",
forceIgnoreFood:"Ignorer la nourriture (a la priorité sur le limiteur)",
resetStats:"Réinitialiser stats",
resetTaggedPlanets:"Réinitialiser les planètes marquées",
resetPinnedPlayers:"Réinitialiser les joueurs épinglés",
resetAll:"Réinitialiser toutes les données OGLight",
resetStatsLong:"Voulez-vous vraiment réinitialiser les stats ?",
resetTaggedPlanetsLong:"Voulez-vous vraiment réinitialiser les planètes marquées ?",
resetPinnedPlayersLong:"Voulez-vous vraiment réinitialiser les joueurs épinglés ?",
resetAllLong:"Voulez-vous vraiment réinitialiser toutes les données OGLight ?",
reportBlackhole:"Signaler un trou noir",
reportBlackholeLong:"Voulez vous vraiment ajouter ce trou noir ?",
emptyPlayerList:"Cette liste de joueurs est vide",
debugMode:"Mode debug",
sim:"Simulateur de combat",
converter:"Convertisseur de combat",
siblingPlanetMoon:"Planète / lune liée",
oglMessageDone:"Ce message a été traité par OGLight",
ptreMessageDone:"Activité envoyée à PTRE",
boardTab:"Afficher les annonces du board",
msu:"Metal standard unit",
notifyNoProbe:"Fonctionnalité desactivée :(",
shortcutsOnRight:"Raccourcis sous le menu des planètes",
ptreTeamKey:"Team key",
ptreLogs:"Afficher les erreurs PTRE",
ptreActivityImported:"Activité importée dans PTRE",
ptreActivityAlreadyImported:"Activité déjà importée dans PTRE",
ptreSyncTarget:"Synchroniser avec PTRE",
ptreManageTarget:"Gérer sur PTRE",
colorblindMode:"Mode daltonien",
fleetQuickCollect:"Collecte rapide des ressources de cette planète",
sidePanelOnLeft:"Panneau latéral à gauche",
galaxyReload:"Recharger la galaxie",
spyTableMSU:"Utiliser le MSU dans le tableau d'espio",
};
this.de =
{
ship:"Schiffe",
item:"Item",
other:"Sonstiges",
resource:"Ressourcen",
battle:"Kampf",
blackhole:"Schwarzes Loch",
early:"Verfrühung",
late:"Verspätung",
trader:"Händler",
nothing:"Nichts",
pirate:"Piraten",
alien:"Aliens",
duration:"Dauer",
defaultShip:"Standard Schiff",
defaultMission:"Standard Mission",
useClientTime:"Nutze Clientzeit",
displayMiniStats:"Zeige Statistik Bereich",
displaySpyTable:"Zeige Spionagetabelle",
displayPlanetTimers:"Zeige Planetentimer",
disablePlanetTooltips:"Deaktiviere Planetenmenü Tooltip",
showMenuResources:"Planeten Menü-Anordnung",
reduceLargeImages:"Klappe große Bilder zu",
ignoreExpeShips:"Ignoriere Schiffsfunde in Expeditionen",
ignoreExpeShipsLoss:"Ignoriere Flottenverluste in Expeditionen",
ignoreConsumption:"Ignoriere Treibstoffverbrauch",
resourceTreshold:"Ressourcen Grenzwert",
tooltipDelay:"Tooltip Verzögerung (ms)",
galaxyUp:"Nächste Galaxie",
galaxyDown:"Vorherige Galaxie",
galaxyLeft:"Vorheriges System",
galaxyRight:"Nächstes System",
previousPlanet:"Vorheriger Planet",
nextPlanet:"Nächster Planet",
nextPinnedPosition:"Nächste angepinnte Position",
fleetRepeat:"Wiederhole letzte Flotte",
fleetSelectAll:"<div>Wähle alle Schiffe (flotte1)<hr>Wähle alle Ressourcen (flotte2)</div>",
expeditionSC:"Kleiner Transporter Expedition",
expeditionLC:"Großer Transporter Expedition",
expeditionPF:"Pathfinder Expedition",
galaxySpySystem:"System Spionage",
collectLinked:"Sammle zu verlinktem Planet/Mond",
keyboardActions:"Tastatureinstellungen",
expeditionValue:"Expedition Maximalwert",
expeditionValueTT:"Benutzerdefinierter Maximalwert für Expeditionen.<br> Setze ihn auf <b>0</b> um berechnete Werte zu verwenden.",
expeditionBigShips:"Erlaubtes größtes Schiff",
expeditionRandomSystem:"Zufälliges System",
expeditionShipRatio:"Schiffsfund Wert(%)",
fleetLimiter:"Flottenbegrenzer",
fleetLimiterTT:"Wähle die Anzahl an Schiffen / Ressourcen die auf dem Planeten bleiben sollen",
menu:"OGLight Einstellungen",
quickRaid:"Schnell-Angriff",
attackNext:"Attackiere nächsten Planeten",
autoCleanReports:"Automatische Spionagebericht-Bereinigung",
noCurrentPin:"Fehler: Kein angepinntes Ziel",
backFirstFleet:"Ziehe erste Flotte zurück",
backLastFleet:"Ziehe letzte Flotte zurück",
fleetReverseAll:"Auswahl umkehren",
fleetResourcesSplit:"Teile Schiffe/Ressourcen",
manageData:"Verwalte OGLight Daten",
profileButton:"Profil Maximalwerte",
limiters:"Maximalwerte",
expeditionRedirect:"Zum nächsten Planet/Mond weiterleiten",
playerProfile:"Spielerprofil",
topReportDetails:"Informationen oberster Bericht",
reportFound:"oberster Bericht",
discovery:"Sende Erkundung",
collectResources:"Ressourcen zusammenziehen",
accountSummary:"Accountzusammenfassung",
stats:"Statistiken",
taggedPlanets:"Getaggte Planeten",
pinnedPlayers:"Angepinnte Spieler",
oglSettings:"OGLight Einstellungen",
coffee:"Unterstütze mich",
syncEmpire:"Synchronisiere Imperiumsdaten",
repeatQueue:"Wiederhole Anzahl in neuer Schleife X mal.<br>Diese Option kann etwas dauern.",
spyPlanet:"Spioniere diesen Planeten",
spyMoon:"Spioniere diesen Mond",
resourceLimiter:"Subtrahiere Anzahl der Ressourcen die im Profilmaximalwert definiert sind.",
fleetLimiter:"Subtrahiere Anzahl der Schiffe die im Profilmaximalwert definiert sind.",
forceKeepCapacity:"Genügend Ladekapazität zurückhalten, um Rohstoffe zu transportieren (hat Priorität über definierten Grenzwerten)",
forceIgnoreFood:"Ignoriere Nahrung (hat Priorität über definierten Grenzwerten)",
resetStats:"Setze Statistik zurück",
resetTaggedPlanets:"Setze getaggte Planeten zurück",
resetPinnedPlayers:"Setze angepinnte Spieler zurück",
resetAll:"Setze alle Daten zurück",
resetStatsLong:"Möchtest du wirklich die OGL Daten zurücksetzen?",
resetTaggedPlanetsLong:"Möchtest du wirklich die getaggten Planeten zurücksetzen?",
resetPinnedPlayersLong:"Möchtest du wirklich die Spielerdaten zurücksetzen?",
resetAllLong:"Möchtest du wirklich alle OGL Daten zurücksetzen?",
reportBlackhole:"Melde schwarzes Loch",
reportBlackholeLong:"Möchtest du dieses Schwarze Loch wirklich hinzufügen?",
emptyPlayerList:"Es ist kein Spieler in der Liste",
debugMode:"Debug Modus",
sim:"Kampfsimulator",
siblingPlanetMoon:"Verknüpfter Planet / Mond",
oglMessageDone:"Diese Nachricht wurde von OGLight gelesen",
boardTab:"Zeige Forum Neuigkeiten an",
msu:"Metall Standardeinheit (MSE)",
notifyNoProbe:"Funktion deaktiviert :(",
shortcutsOnRight:"Zeige Kurzmenü unter Planeten",
ptreTeamKey:"PTRE Team Key",
ptreLogs:"Zeige PTRE Fehler",
ptreActivityImported:"Aktivität zu PTRE importiert",
ptreActivityAlreadyImported:"Aktivität bereits im PTRE",
ptreSyncTarget:"Synchronisiere mit PTRE",
ptreManageTarget:"Verwalte auf PTRE"
};
this.gr =
{
ship:"Πλοία",
item:"Αντικείμενο",
other:"Άλλο",
resource:"Πόροι",
battle:"Μάχη",
blackhole:"Μαύρη τρύπα",
early:"Νωρίς",
late:"Αργά",
trader:"Εμπόριο",
nothing:"Τίποτα",
pirate:"Πειρατές",
alien:"Άλιεν ",
duration:"Διάρκεια",
defaultShip:"Προεπιλογή πλοίου",
defaultMission:"Προεπιλεγμένη αποστολή",
useClientTime:"Χρήση ρολογιού OGlight",
displayMiniStats:"Εύρος στατιστικών",
displaySpyTable:"Πίνακας κατασκοπείας",
displayPlanetTimers:"Χρόνος δραστηριότητας",
disablePlanetTooltips:"Απενεργοποίηση μενού πλανητών",
showMenuResources:"Διάταξη μενού πλανητών",
reduceLargeImages:"Μικρότερες εικόνες",
ignoreExpeShips:"Αγνόησε πλοία που βρέθηκαν σε αποστολές",
ignoreExpeShipsLoss:"Αγνόησε πλοία που χάθηκαν σε αποστολές",
ignoreConsumption:"Αγνόησε την κατανάλωση πλοίων",
resourceTreshold:"Ανώτατο όριο πόρων",
tooltipDelay:"Καθυστέρηση επεξήγησης (ms)",
galaxyUp:"Επόμενος γαλαξίας",
galaxyDown:"Προηγούμενος γαλαξίας",
galaxyLeft:"Προηγούμενο σύστημα",
galaxyRight:"Επόμενο σύστημα",
previousPlanet:"Προηγούμενος πλανήτης",
nextPlanet:"Επόμενος πλανήτης",
nextPinnedPosition:"Επόμενη καρφιτσωμένη θέση",
fleetRepeat:"Επανάληψη τελευταίου στόλου",
fleetSelectAll:"<div>Επιλογή όλων των πλοίων (fleet1)<hr>Επιλογή όλων των πόρων (fleet2)</div>",
expeditionSC:'Αποστολή με μικρά μεταγωγικά',
expeditionLC:'Αποστολή με μεγάλα μεταγωγικά',
expeditionPF:'Αποστολή με pathfinder',
galaxySpySystem:"Κατασκοπεία συστήματος",
collectLinked:"Συλλογή στο συνδεδεμένο πλανήτη/φεγγάρι",
keyboardActions:"Ρυθμίσεις πληκτρολογίου",
expeditionValue:"Αξία αποστολής",
expeditionValueTT:"Προσαρμοσμένη αξία των αποστολών.<br> Ρύθμιση σε <b>0</b> για να χρησιμοποιηθεί η προεπιλεγμένη τιμή",
expeditionBigShips:"Επιτρέπονται μεγαλύτερα πλοία",
expeditionRandomSystem:"Τυχαίο σύστημα",
expeditionShipRatio:"Αξία πλοίων που βρέθηκαν (%)",
fleetLimiter:"Περιοριστής στόλου",
fleetLimiterTT:"Επιλέξτε την ποσότητα πλοίων / πόρων που θα παραμείνουν στον πλανήτη",
menu:"Εναλλαγή μενού OGLight",
quickRaid:"Γρήγορη επιδρομή",
attackNext:"Επίθεση στον επόμενο πλανήτη",
autoCleanReports:"Αυτόματο σβήσιμο αναφορών",
noCurrentPin:"Σφάλμα, δεν καρφιτσώθηκε στόχος",
backFirstFleet:"Επιστροφή πρώτος στόλος",
backLastFleet:"Επιστροφή τελευταίος στόλος",
fleetReverseAll:"Αντίστροφη επιλογή",
fleetResourcesSplit:"Διαχωρισμός πλοίων/πόρων",
manageData:"Διαχείριση δεδομένων OGLight",
profileButton:"Προφίλ περιορισμού",
limiters:"Περιορισμοί",
expeditionRedirect:"Ανακατεύθυνση στον επόμενο πλανήτη/φεγγάρι",
playerProfile:"Προφίλ παίχτη",
topReportDetails:"Λεπτομέρειες κορυφαίας αναφοράς",
reportFound:"Κορυφαία αναφορά",
discovery:"Μαζική Αποστολή Ανιχνευτικών Σκαφών",
collectResources:"Συλλογή πόρων",
accountSummary:"Περίληψη λογαριασμού",
stats:"Στατιστικά",
taggedPlanets:"Πλανήτες με ετικέτα",
pinnedPlayers:"Καρφιτσωμένοι παίκτες",
oglSettings:"Ρυθμίσεις OGLight",
coffee:"Buy me a coffee",
syncEmpire:"Συγχρονισμός δεδομένων",
repeatQueue:"Επανέλαβε το παραπάνω ποσό σε νέα ουρά X χρόνο.<br>Αυτή η λειτουργία μπορεί να διαρκέσει λίγο",
spyPlanet:"Κατασκοπεία αυτού του πλανήτη",
spyMoon:"Κατασκοπεία αυτού του φεγγαριού",
resourceLimiter:"Αφαιρέστε το ποσό των πόρων που ορίζονται στον περιοριστή ",
fleetLimiter:"Αφαιρέστε τον αριθμό των πλοίων που ορίζεται στον περιοριστή ",
forceKeepCapacity:"Διατηρήστε αρκετή ποσότητα στον πλανήτη σας για να μεταφέρετε τους πόρους σας(has priority over limiters)",
forceIgnoreFood:"Αγνόησε την τροφή (has priority over limiters)",
resetStats:"Επαναφορά στατιστικών",
resetTaggedPlanets:"Επαναφορά πλανητών με ετικέτα",
resetPinnedPlayers:"Επαναφορά καρφιτσωμένων παικτών ",
resetAll:"Επαναφορά όλων των δεδομένων",
resetStatsLong:"Θέλετε να επαναφέρετε τα δεδομένα των στατιστικών του OGLight;",
resetTaggedPlanetsLong:"Θέλετε να επαναφέρετε τα δεδομένα πλανητών με ετικέτα του OGLight;",
resetPinnedPlayersLong:"Θέλετε να επαναφέρετε τα δεδομένα των καρφιτσωμένων παικτών του OGLight;",
resetAllLong:"Θέλετε να επαναφέρετε όλα τα δεδομένα του OGLight;",
reportBlackhole:"Ανάφερε μια μαύρη τρύπα",
reportBlackholeLong:"Θέλετε να προσθέσετε αυτή την μαύρη τρύπα;",
emptyPlayerList:"Δεν υπάρχει παίχτης σε αυτή τη λίστα",
debugMode:"Εντοπισμός σφαλμάτων",
sim:"Προσομοιωτής μάχης",
siblingPlanetMoon:"Αδελφός πλανήτης / φεγγάρι",
oglMessageDone:"Αυτό το μήνυμα διαβάστηκε από το OGLight",
boardTab:"Εμφάνιση πίνακα ειδήσεων",
msu:"Αξια σε Μέταλλο",
notifyNoProbe:"Απενεργοποιημένη δυνατότητα :(",
shortcutsOnRight:"Εμφάνιση συντομεύσεων κάτω από τους πλανήτες",
ptreTeamKey:"Team key",
ptreLogs:"Εμφάνισε PTRE σφάλματα",
ptreActivityImported:"δραστηριότητα εισήχθη στο PTRE",
ptreActivityAlreadyImported:"δραστηριότητα που έχει ήδη εισαχθεί PTRE",
ptreSyncTarget:"Συγχρονισμός με PTRE",
ptreManageTarget:"Διαχείριση PTRE",
};
}
find(key, isRaw)
{
if(key == 'darkmatter') key = 'dm';
if(isRaw && this.raw[key]) return this.raw[key];
else if(this[this.ogl.account.lang] && this[this.ogl.account.lang][key]) return this[this.ogl.account.lang][key];
else if(this.ogl.db.serverData[key]) return this.ogl.db.serverData[key];
else if(this.en[key]) return this.en[key];
else return 'TEXT_NOT_FOUND';
}
}
class TimeManager extends Manager
{
load()
{
this.units = LocalizationStrings.timeunits.short;
this.serverTimeZoneOffset = this.ogl.db.serverData.serverTimeZoneOffsetInMinutes * 60000;
//this.clientTimeZoneOffset = serverTime.getTimezoneOffset() * 60000;
this.clientTimeZoneOffset = Math.round((serverTime.getTime() - Date.now()) / (1000 * 60 * 60)) * 60 * 60000;
// times at script load; /!\ those values are not refreshed
this.UTC = serverTime.getTime() + this.serverTimeZoneOffset;
this.serverTime = serverTime.getTime();
this.clientTime = this.UTC - this.clientTimeZoneOffset;
this.observeList = ['.OGameClock', '.ogl_backTimer', '.ogl_backWrapper'];
//this.observeList = ['.OGameClock', '#fleet2 #arrivalTime', '#fleet2 #returnTime', '.ogl_backTimer', '.ogl_backWrapper'];
this.updateList = ['.OGameClock', '.arrivalTime', '.absTime', '.nextabsTime', '.ui-dialog .msg_date'];
this.productionBoxes =
{
restTimebuilding:'productionboxbuildingcomponent', // base building
restTimeresearch:'productionboxresearchcomponent', // base research
restTimeship2:'productionboxshipyardcomponent', // base ships
restTimelfbuilding:'productionboxlfbuildingcomponent', // lifeform building
restTimelfresearch:'productionboxlfresearchcomponent', // lifeform research
mecha:'productionboxextendedshipyardcomponent', // mecha ships
};
if(this.ogl.page == 'fleetdispatch')
{
// update fleet2 arrival / back time to be much more precise
let lastLoop = 0;
let arrivalDom, backDom;
document.querySelectorAll('#fleet2 #arrivalTime, #fleet2 #returnTime').forEach((e, index) =>
{
if(index == 0) arrivalDom = Util.addDom('div', { class:'ogl_missionTime ogl_arrival', parent:e.parentNode, child:'loading...' });
else backDom = Util.addDom('div', { class:'ogl_missionTime ogl_return', parent:e.parentNode, child:'loading...' });
e.remove();
});
this.timeLoop = noLoop =>
{
//const time = serverTime.getTime();
const timeObj = this.getObj();
if(unsafeWindow.fleetDispatcher && (timeObj.server != lastLoop || noLoop))
{
const duration = (fleetDispatcher.getDuration() || 0) * 1000;
const arrival = new Date(duration + (this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server));
const back = new Date(fleetDispatcher.mission == 15 ? duration * 2 + (this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server) + fleetDispatcher.expeditionTime * 3600000 :
fleetDispatcher.mission == 5 ? duration * 2 + (this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server) + fleetDispatcher.holdingTime * 3600000 :
duration * 2 + (this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server));
arrivalDom.setAttribute('data-output-date', arrival.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'}));
arrivalDom.setAttribute('data-output-time', arrival.toLocaleTimeString('de-DE'));
backDom.setAttribute('data-output-date', back.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'}));
backDom.setAttribute('data-output-time', back.toLocaleTimeString('de-DE'));
lastLoop = timeObj.server;
}
if(!noLoop) requestAnimationFrame(() => this.timeLoop());
}
this.timeLoop();
}
// ping
const ping = (performance.timing.responseEnd - performance.timing.requestStart) / 1000;
let li = Util.addDom('li', { 'class':'ogl_ping', child:`${ping} s`, parent:document.querySelector('#bar ul') });
if(ping >= 2) li.classList.add('ogl_danger');
else if(ping >= 1) li.classList.add('ogl_warning');
Util.runAsync(this.update, this);
Util.runAsync(this.observe, this);
}
update(self, domTarget)
{
self = self || this;
self.updateList.forEach(element =>
{
let targets = domTarget ? [domTarget] : document.querySelectorAll(`${element}:not(.ogl_updated)`);
targets.forEach(target =>
{
target.classList.add('ogl_updated');
const timeObj = self.getObj(self.dateStringToTime(target.innerText));
const date = new Date(self.ogl.db.options.useClientTime ? timeObj.client : timeObj.server);
if(target.innerText.split(/\.|:| /).length > 5)
{
target.setAttribute('data-output-date', date.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'}));
//target.setAttribute('data-time-utc', timeObj.utc);
}
target.setAttribute('data-output-time', date.toLocaleTimeString('de-DE'));
target.setAttribute('data-time-server', timeObj.server);
target.setAttribute('data-time-client', timeObj.client);
});
});
}
observe(self)
{
self = self || this;
self.observeList.forEach(element =>
{
let targets = document.querySelectorAll(`${element}:not(.ogl_observed)`);
targets.forEach(target =>
{
target.classList.add('ogl_observed');
let action = () =>
{
const timeObj = self.getObj(self.dateStringToTime(target.innerText));
const date = new Date(self.ogl.db.options.useClientTime ? timeObj.client : timeObj.server);
target.setAttribute('data-output-date', date.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'}));
target.setAttribute('data-output-time', date.toLocaleTimeString('de-DE'));
//target.setAttribute('data-time-utc', timeObj.utc);
target.setAttribute('data-time-server', timeObj.server);
target.setAttribute('data-time-client', timeObj.client);
}
action();
Util.observe(target, {childList:true}, action);
});
});
}
getObj(time, timeSource)
{
timeSource = timeSource || 'server';
time = time || (timeSource == 'server' ? serverTime.getTime() : Date.now());
const timezone = {};
timezone.serverOffset = 0;
timezone.clientOffset = Math.round((serverTime.getTime() - Date.now()) / (1000 * 60 * 60)) * 60 * 60000;
if(timeSource == 'server')
{
timezone.client = time - timezone.clientOffset;
timezone.server = time;
}
else
{
timezone.client = time;
timezone.server = time + timezone.clientOffset;
}
return timezone;
}
convertTimestampToDate(timestamp, full)
{
const date = new Date(timestamp);
let target = Util.addDom('time', { child:date.toLocaleTimeString('de-DE') });
if(full)
{
target = Util.addDom('time', { child:`${date.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})} ${date.toLocaleTimeString('de-DE')}` });
}
return target;
}
updateMovements()
{
const initialTime = new Date();
document.querySelectorAll('[data-mission-type]').forEach(fleet =>
{
if(fleet.querySelector('.ogl_backTimer')) return;
const backButton = fleet.querySelector('.reversal_time a');
if(!backButton) return;
const domElement = Util.addDom('div', { class:'ogl_backTimer ogl_button', parent:fleet.querySelector('.ogl_resourcesBlock'), onclick:() => backButton.click() });
let time = backButton.getAttribute('data-tooltip-title') || backButton.getAttribute('title');
if(!time) return;
time = time.replace('<br>',' ');
time = time.replace(/ \.$/, '');
time = time.trim().replace(/[ \.]/g, ':');
time = time.split(':');
time = new Date(`${time[4]}-${time[3]}-${time[2]}T${time[5]}:${time[6]}:${time[7]}`).getTime();
this.updateBackTimer(initialTime, time, domElement);
const wrapper = Util.addDom('div');
Util.addDom('div', { class:'ogl_backWrapper', parent:wrapper, child:domElement.innerText });
backButton.addEventListener('tooltip', () => backButton._tippy.setContent(wrapper));
//backButton.addEventListener('tooltip', () => this.ogl._tooltip.update(wrapper));
const interval = setInterval(() =>
{
if(document.body.contains(fleet)) this.updateBackTimer(initialTime, time, domElement);
else clearInterval(interval);
}, 500);
});
}
updateBackTimer(initialTime, time, domElement)
{
const timeObj = this.getObj(time);
const deltaTime = new Date() - initialTime;
const newTime = new Date(timeObj.server + deltaTime * 2);
domElement.innerText = `${newTime.toLocaleDateString('de-DE')} ${newTime.toLocaleTimeString('de-DE')}`;
}
dateStringToTime(str)
{
str = str.split(/\.|:| /);
if(str.length <= 5)
{
str = ["01","01","2000"].concat(str);
}
str = str.map(e => e.padStart(2, '0'));
if(str[2].length == 2) str[2] = '20' + str[2]; // ex: 10.05.22 => 10.05.2022
return new Date(`${str[2]}-${str[1]}-${str[0]}T${str[3]}:${str[4]}:${str[5]}`).getTime();
}
timeToKey(time) // can only receive server time
{
const dateObj = new Date(this.getObj(time, 'server').server);
return `${dateObj.getFullYear()}-${('0' + (dateObj.getMonth() + 1)).slice(-2)}-${('0' + dateObj.getDate()).slice(-2)}`;
}
timeToHMS(time)
{
//return new Date(time).toISOString().slice(11, 19);
return new Date(time).toLocaleTimeString('de-DE', { hour12:false });
}
durationToHMS(duration)
{
const totalSeconds = Math.floor(duration / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
const pad = (num) => num.toString().padStart(2, '0');
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
}
stringToTime(str)
{
if(!str) return;
const pattern = `(\\d+)(?:${this.units.hour}|${this.units.minute}|${this.units.second})`;
const regex = new RegExp(pattern, 'g');
const match = str.match(regex);
if(!match) return 0;
const hMatch = match.find(e => e.indexOf(this.units.hour) >= 0);
const mMatch = match.find(e => e.indexOf(this.units.minute) >= 0);
const sMatch = match.find(e => e.indexOf(this.units.second) >= 0);
const hour = hMatch ? parseInt(hMatch.replace(/\D/g, '')) : 0;
const minute = mMatch ? parseInt(mMatch.replace(/\D/g, '')) : 0;
const second = sMatch ? parseInt(sMatch.replace(/\D/g, '')) : 0;
const ms = ((hour * 3600) + (minute * 60) + second) * 1000;
return ms;
}
isoDurationToMs = (isoStr) =>
{
const regex = /P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:([\d.]+)S)?)?/;
const parts = isoStr.match(regex);
if(!parts) return 0;
const [, , , weeks, days, hours, minutes, seconds] = parts.map(p => parseFloat(p) || 0);
return (
weeks * 7 * 86400000 + // 1 semaine = 7 jours
days * 86400000 +
hours * 3600000 +
minutes * 60000 +
seconds * 1000
);
}
}
class FetchManager extends Manager
{
load()
{
this.fetched = { empire0:1, empire1:1, lf:1, prod:1 };
this.fetchedError = { empire0:0, empire1:0, lf:0, prod:0 };
this.apiCooldown = 86400000 * 7;
this.pending = [];
setInterval(() => this.resolve(), 500);
}
resolve()
{
if(this.pending.length < 1) return;
let inProgress = this.pending.splice(0, 7);
Promise.all(inProgress.map(promise => fetch(promise.url).then(response => response.text()).then(text => { return {'result':text, 'callback':promise.callback} }))).then(reqs =>
{
reqs.forEach(req =>
{
req.callback(req.result);
});
});
}
fetchMainData(callback, ignoreDelay)
{
this.ogl._topbar?.syncBtn.classList.add('ogl_active');
Promise.all([
this.fetchLFBonuses(false, ignoreDelay),
this.fetchEmpire(0, false, ignoreDelay),
this.fetchEmpire(1, false, ignoreDelay),
this.fetchProductionQueue(false, ignoreDelay)
])
.then(results =>
{
this.ogl._topbar.syncBtn.classList.remove('ogl_active');
this.ogl.save();
if(callback) callback();
})
.catch(error =>
{
this.ogl._topbar.syncBtn.classList.remove('ogl_active');
console.error(`Fetch error`);
});
}
async fetchEmpire(type, callback, ignoreDelay)
{
type = type || 0;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
this.ogl.db[`lastEmpire${type}Update`] = this.ogl.db[`lastEmpire${type}Update`] || 0;
if(!ignoreDelay && Date.now() < this.ogl.db[`lastEmpire${type}Update`] + 60000 * 3) return; // 3mn
return fetch(`https://${window.location.host}/game/index.php?page=ajax&component=empire&ajax=1&planetType=${type}&asJson=1`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' },
signal: controller.signal
})
.then(response =>
{
clearTimeout(timeout);
return response.json();
})
.then(result =>
{
this.ogl._empire.update(JSON.parse(result.mergedArray), type);
if(callback) callback();
})
.catch(error =>
{
console.error(`Can't fetch empire data`);
});
}
async fetchLFBonuses(callback, ignoreDelay)
{
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
this.ogl.db.lastLFBonusUpdate = this.ogl.db.lastLFBonusUpdate || 0;
if(!ignoreDelay && Date.now() < this.ogl.db.lastLFBonusUpdate + 60000 * 4) return; // 4mn
return fetch(`https://${window.location.host}/game/index.php?page=ajax&component=lfbonuses`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' },
signal: controller.signal
})
.then(response =>
{
clearTimeout(timeout);
return response.text();
})
.then(result =>
{
let xml = new DOMParser().parseFromString(result, 'text/html');
if(!xml.querySelector('.lfsettingsContentWrapper')) return;
this.ogl._empire.getLFBonuses(xml);
this.ogl.db.lastLFBonusUpdate = Date.now();
if(callback) callback();
})
.catch(error =>
{
console.error(`Can't fetch LF data`);
});
}
async fetchProductionQueue(callback, ignoreDelay)
{
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
this.ogl.db.lastProductionQueueUpdate = this.ogl.db.lastProductionQueueUpdate || 0;
if(!ignoreDelay && Date.now() < this.ogl.db.lastProductionQueueUpdate + 10000) return; // 10sec
return fetch(`https://${window.location.host}/game/index.php?page=ajax&component=productionqueue&ajax=1`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' },
signal: controller.signal
})
.then(response =>
{
clearTimeout(timeout);
return response.text();
})
.then(result =>
{
const xml = new DOMParser().parseFromString(result, 'text/html');
const hasResearch = xml.querySelector(`.research time`);
Object.values(this.ogl._dom.planet).forEach(planet =>
{
const id = planet._ogl.id;
const times =
{
baseBuilding:xml.querySelector(`time.building${id}`),
//baseResearch:xml.querySelector(`time.research${id}`),
ship:xml.querySelector(`time.ship${id}`),
lfBuilding:xml.querySelector(`time.lfbuilding${id}`),
lfResearch:xml.querySelector(`time.lfresearch${id}`),
mechaShip:xml.querySelector(`time.ship_2nd${id}`),
}
this.ogl.db.myPlanets[id].upgrades = this.ogl.db.myPlanets[id].upgrades || {}
for(let [key] of Object.entries(times))
{
if(times[key])
{
const level = times[key].closest('.productionDetails')?.querySelector('.productionLevel')?.innerText?.replace(/\D/g,'') || '0'; // 0 for ships/defs
const entry = {};
entry.name = times[key].closest('.productionDetails').querySelector('.productionName').childNodes[0].textContent.trim();
const entryID = Object.entries(this.ogl.db.serverData || {}).find(e => e[1] == entry.name);
entry.id = entryID ? parseInt(entryID[0]) : -1;
entry.lvl = parseInt(level);
entry.end = parseInt(times[key].getAttribute('data-end')) * 1000;
entry.type = key;
this.ogl.db.myPlanets[id].upgrades[key] = [entry];
}
else
{
this.ogl.db.myPlanets[id].upgrades[key] = [];
}
if(!hasResearch)
{
delete this.ogl.db.myPlanets[id].upgrades.baseResearch;
}
}
});
this.ogl._topbar.checkUpgrade();
this.ogl.db.lastProductionQueueUpdate = Date.now();
if(callback) callback();
})
.catch(error =>
{
console.error(`Can't fetch production queue data`);
});
}
async fetchStatus(callback, ignoreDelay)
{
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
this.ogl.db.lastStatusUpdate = this.ogl.db.lastStatusUpdate || 0;
if(!ignoreDelay && serverTime.getTime() < this.ogl.db.lastStatusUpdate + 1000 * 4000) return; // 1h+
const getMainStatus = status =>
{
if(status.indexOf('v') > -1) status = 'v';
else if(status.indexOf('I') > -1) status = 'I';
else if(status.indexOf('i') > -1) status = 'i';
else if(status.indexOf('o') > -1) status = 'o';
else if(status.indexOf('b') > -1) status = 'b';
else status = 'n';
return status;
}
return fetch(`https://${window.location.host}/api/players.xml`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' },
signal: controller.signal
})
.then(response =>
{
clearTimeout(timeout);
return response.text();
})
.then(result =>
{
const xml = new DOMParser().parseFromString(result, 'text/xml');
const apiTime = parseInt(xml.querySelector('players').getAttribute('timestamp')) * 1000;
xml.querySelectorAll('player').forEach(entry =>
{
const id = parseInt(entry.getAttribute('id'));
const name = entry.getAttribute('name');
const status = entry.getAttribute('status') || 'n';
const player = this.ogl.db.udb[id];
if(player && apiTime > (player.liveUpdate || 0))
{
const newStatus = getMainStatus(status);
player.name = name;
if(player?.status != 'HONORABLE' || newStatus != 'n') player.status = newStatus;
}
});
this.ogl.db.lastStatusUpdate = Date.now();
});
}
fetchPlayerAPI(id, name, afterAjax)
{
if(!id) return;
const player = this.ogl.db.udb[id] || this.ogl.createPlayer(id);
player.uid = player.uid || id;
player.api = player.api || 0;
player.planets = player.planets || [];
player.name = name || player.name;
if(serverTime.getTime() - player.api > this.apiCooldown)
{
this.pending.push(
{
url:`https://${window.location.host}/api/playerData.xml?id=${player.uid}`,
callback:data =>
{
const xml = new DOMParser().parseFromString(data, 'text/html');
if(!xml.querySelector('playerdata'))
{
if(this.ogl.db.currentSide == player.uid)
{
delete this.ogl.db.udb[id];
const container = Util.addDom('div');
Util.addDom('div', { parent:container, class:'material-icons ogl_back', child:'arrow_back', onclick:() => { this.ogl._topbar.openPinned() } });
Util.addDom('div', { parent:container, child:data });
this.ogl._ui.openSide(container, player.uid);
}
return;
}
const apiTime = parseInt(xml.querySelector('playerdata').getAttribute('timestamp')) * 1000;
if(!player.name) player.name = xml.querySelector('playerdata').getAttribute('name');
player.score = player.score || {};
// score
player.score.global = Math.floor(xml.querySelector('positions position[type="0"]').getAttribute('score'));
player.score.economy = Math.floor(xml.querySelector('positions position[type="1"]').getAttribute('score'));
player.score.research = Math.floor(xml.querySelector('positions position[type="2"]').getAttribute('score'));
player.score.lifeform = Math.floor(xml.querySelector('positions position[type="8"]').getAttribute('score'));
player.score.military = Math.floor(xml.querySelector('positions position[type="3"]').getAttribute('score'));
// ranking
player.score.globalRanking = Math.floor(xml.querySelector('positions position[type="0"]').innerText);
player.score.economyRanking = Math.floor(xml.querySelector('positions position[type="1"]').innerText);
player.score.researchRanking = Math.floor(xml.querySelector('positions position[type="2"]').innerText);
player.score.lifeformRanking = Math.floor(xml.querySelector('positions position[type="8"]').innerText);
player.score.militaryRanking = Math.floor(xml.querySelector('positions position[type="3"]').innerText);
player.api = apiTime;
xml.querySelectorAll('planet').forEach((element, index) =>
{
const pid = element.getAttribute('id');
const coords = element.getAttribute('coords');
const moon = element.querySelector('moon')?.getAttribute('id');
this.ogl.db.pdb[coords] = this.ogl.db.pdb[coords] || {};
const planet = this.ogl.db.pdb[coords];
planet.api = planet.api || 0;
if(planet.api <= apiTime)
{
planet.uid = player.uid;
planet.pid = pid;
planet.mid = moon;
planet.coo = coords;
planet.api = apiTime;
if(index == 0) planet.home = true;
}
if(player.planets.indexOf(coords) < 0) player.planets.push(coords);
});
// clear old planets
player.planets.forEach((coords, index) =>
{
if(this.ogl.db.pdb[coords]?.api < apiTime)
{
player.planets.splice(index, 1);
if(this.ogl.db.pdb[coords].uid == player.uid) delete this.ogl.db.pdb[coords];
}
});
if(afterAjax) afterAjax();
}
});
}
else // no api request required
{
if(afterAjax) afterAjax(false);
}
}
}
class UIManager extends Manager
{
load(reloaded)
{
// build side panel
if(!document.querySelector('.ogl_side'))
{
this.side = Util.addDom('div', { class:`ogl_side ${this.ogl.db.currentSide ? 'ogl_active': ''}`, parent:document.body });
}
if(!reloaded)
{
Util.addDom('li', { before:this.ogl._dom.mainClock, child:this.ogl._dom.countColonies.innerText });
this.checkImportExport();
}
this.attachGlobalClickEvent(reloaded);
this.displayResourcesRecap();
this.groupPlanets();
}
openSide(dom, pin, buttonSource)
{
let closeBtn = Util.addDom('div', {class:'material-icons ogl_close', child:'close', onclick:() =>
{
this.side.classList.remove('ogl_active');
delete this.ogl.db.currentSide;
this.ogl._shortcut.load();
this.ogl._shortcut.updateShortcutsPosition();
}});
if(buttonSource && this.ogl.db.currentSide == pin && !this.side.querySelector('.ogl_loading'))
{
closeBtn.click();
return;
}
this.side.innerText = '';
this.side.appendChild(closeBtn);
this.side.appendChild(dom);
this.side.classList.add('ogl_active');
if(this.lastOpenedSide != pin) this.ogl._shortcut.load(); // refresh shortcuts
this.ogl.db.currentSide = pin;
this.lastOpenedSide = pin;
this.ogl._shortcut.updateShortcutsPosition();
document.querySelectorAll('.ogl_inputCheck').forEach(e => Util.formatInput(e));
if(this.ogl._tooltip) this.ogl._tooltip.initTooltipList(this.side.querySelectorAll(getTooltipSelector()));
}
attachGlobalClickEvent(reloaded)
{
if(!reloaded)
{
document.addEventListener('keyup', event =>
{
let activeElement = document.activeElement.tagName;
if(activeElement == 'INPUT' || activeElement == 'TEXTAREA')
{
if(document.activeElement.classList.contains('ogl_inputCheck'))
{
Util.formatInput(document.activeElement);
}
}
});
document.querySelectorAll('.planetlink, .moonlink').forEach(target =>
{
target.addEventListener('pointerenter', event =>
{
if(!unsafeWindow.fleetDispatcher || !this.ogl._fleet?.isReady || !document.body.classList.contains('ogl_destinationPicker')) return;
if(fleetDispatcher.fetchTargetPlayerDataTimeout) return;
//fleetDispatcher.realTarget = JSON.parse(JSON.stringify(fleetDispatcher.targetPlanet));
const coords = event.target.closest('.smallplanet').querySelector('.planet-koords').innerText.split(':');
const type = event.target.classList.contains('moonlink') ? 3 : 1;
const name = type == 3 ? event.target.querySelector('.icon-moon').getAttribute('alt') : event.target.querySelector('.planetPic').getAttribute('alt');
document.querySelector('#galaxy').value = fleetDispatcher.targetPlanet.galaxy;
document.querySelector('#system').value = fleetDispatcher.targetPlanet.system;
document.querySelector('#position').value = fleetDispatcher.targetPlanet.position;
fleetDispatcher.targetPlanet.type = type;
fleetDispatcher.targetPlanet.galaxy = coords[0];
fleetDispatcher.targetPlanet.system = coords[1];
fleetDispatcher.targetPlanet.position = coords[2];
fleetDispatcher.targetPlanet.name = name;
fleetDispatcher.refresh();
});
target.addEventListener('pointerleave', () =>
{
if(/Android|iPhone/i.test(navigator.userAgent)) return;
if(!unsafeWindow.fleetDispatcher || !this.ogl._fleet?.isReady || !document.body.classList.contains('ogl_destinationPicker')) return;
document.querySelector('#galaxy').value = fleetDispatcher.realTarget.galaxy;
document.querySelector('#system').value = fleetDispatcher.realTarget.system;
document.querySelector('#position').value = fleetDispatcher.realTarget.position;
fleetDispatcher.targetPlanet.galaxy = fleetDispatcher.realTarget.galaxy;
fleetDispatcher.targetPlanet.system = fleetDispatcher.realTarget.system;
fleetDispatcher.targetPlanet.position = fleetDispatcher.realTarget.position;
fleetDispatcher.targetPlanet.type = fleetDispatcher.realTarget.type;
fleetDispatcher.targetPlanet.name = fleetDispatcher.realTarget.name;
fleetDispatcher.refresh();
});
});
document.addEventListener('click', event =>
{
if(event.target.tagName == 'svg' || event.target.tagName == 'path') return;
if(event.target.getAttribute('data-galaxy'))
{
let coords = event.target.getAttribute('data-galaxy').split(':');
if(this.ogl.page === 'galaxy')
{
galaxy = coords[0];
system = coords[1];
loadContentNew(galaxy, system);
}
else
{
const url = `https://${window.location.host}/game/index.php?page=ingame&component=galaxy&galaxy=${coords[0]}&system=${coords[1]}`;
if(event.ctrlKey) window.open(url, '_blank');
else window.location.href = url;
}
}
if(event.target.classList.contains('planetlink') || event.target.classList.contains('moonlink')
|| event.target.closest('.planetlink, .moonlink'))
{
if(document.body.classList.contains('ogl_destinationPicker'))
{
event.preventDefault();
const coords = event.target.closest('.smallplanet').querySelector('.planet-koords').innerText.split(':');
const type = event.target.closest('.planetlink, .moonlink').classList.contains('moonlink') ? 3 : 1;
const name = type == 3 ? event.target.closest('.smallplanet').querySelector('.icon-moon').getAttribute('alt') : event.target.closest('.smallplanet').querySelector('.planetPic').getAttribute('alt');
const planet = this.ogl.account.planets.getByCoords(coords.join(':'));
const id = type == 3 ? planet.moonID : planet.id;
if(document.body.classList.contains('ogl_initHarvest'))
{
const firstSource = this.ogl.account.planets.getCurrent();
const firstSourceId = firstSource.currentType == 'moon' ? firstSource.moonID : firstSource.id;
window.location.href = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=${type}&oglmode=1&ogldestinationid=${id}&oglfirstsourceid=${firstSourceId}&ogldestinationtype=${type == 3 ? 'moon' : 'planet'}`;
}
else
{
if(!unsafeWindow.fleetDispatcher || !this.ogl._fleet?.isReady) return;
fleetDispatcher.targetPlanet.type = type;
fleetDispatcher.targetPlanet.galaxy = coords[0];
fleetDispatcher.targetPlanet.system = coords[1];
fleetDispatcher.targetPlanet.position = coords[2];
fleetDispatcher.targetPlanet.name = name;
fleetDispatcher.refresh();
this.ogl._fleet.setRealTarget(JSON.parse(JSON.stringify(fleetDispatcher.targetPlanet)));
if(fleetDispatcher.currentPage == 'fleet1')
{
fleetDispatcher.focusSubmitFleet1();
}
else if(fleetDispatcher.currentPage == 'fleet2')
{
fleetDispatcher.focusSendFleet();
fleetDispatcher.updateTarget();
}
}
}
}
if(event.target.getAttribute('data-api-code')) // copy api code
{
navigator.clipboard.writeText(event.target.getAttribute('data-api-code'));
fadeBox('API code copied');
}
if(event.target.classList.contains('js_actionKillAll')) // clear ogl reports cache
{
if(ogame?.messages?.getCurrentMessageTab() == 20)
{
ogl.cache.reports = {};
}
}
});
}
}
openFleetProfile()
{
const inputKeys = ['metal', 'crystal', 'deut', 'food', 'space', ...this.ogl.shipsList];
const container = Util.addDom('div', { class:'ogl_limiterSettings' });
Util.addDom('h2', { child:'Limiters settings', parent:container });
const grid = Util.addDom('div', { class:'ogl_grid', parent:container });
const dataKey = { planet:'data', moon:'moonData', jumpgate:'jumpgateData' };
const iconKey = { planet:'planet', moon:'bedtime', jumpgate:'door_back' };
['', 'planet', 'moon', 'jumpgate'].forEach(type =>
{
const column = Util.addDom('div', { class:'ogl_limiterColumn', parent:grid });
const header = Util.addDom('div', { class:'ogl_header', parent:column, child:`<div><i class="material-icons">${iconKey[type] || ''}</i> ${type}</div>` });
const action = Util.addDom('div', { class:'ogl_limiterColumnAction', parent:header });
if(type !== '')
{
['planet', 'moon', 'jumpgate'].forEach(syncFrom =>
{
const btn = Util.addDom('div', { parent:action, class:'ogl_syncLimiter ogl_button tooltip', title:`Same as ${syncFrom}`, child:`<i class="material-icons">${iconKey[syncFrom]}</i>`, onclick:() =>
{
this.ogl.db.fleetLimiter[dataKey[type]] = JSON.parse(JSON.stringify(this.ogl.db.fleetLimiter[dataKey[syncFrom]]));
// clear jumpgate resources
delete this.ogl.db.fleetLimiter[dataKey['jumpgate']].metal;
delete this.ogl.db.fleetLimiter[dataKey['jumpgate']].crystal;
delete this.ogl.db.fleetLimiter[dataKey['jumpgate']].deut;
delete this.ogl.db.fleetLimiter[dataKey['jumpgate']].food;
this.ogl._fleet.updateLimiter();
this.ogl._jumpgate.updateLimiter();
Util.runAsync(() => this.openFleetProfile()).then(e => this.ogl._popup.open(e));
}});
if(type === syncFrom) btn.classList.add('ogl_disabled');
});
}
inputKeys.forEach(key =>
{
if(key == 'space')
{
Util.addDom('br', { parent:column });
}
else
{
if(type == '')
{
Util.addDom('div', { class:`ogl_icon ogl_${key}`, parent:column });
}
else
{
const input = Util.addDom('input', { class:`ogl_inputCheck ogl_inputField ogl_${key}`, parent:column, value:this.ogl.db.fleetLimiter?.[dataKey[type]]?.[key] || 0, oninput:() =>
{
setTimeout(() =>
{
this.ogl.db.fleetLimiter[dataKey[type]][key] = parseInt(input.value.replace(/\D/g, '')) || 0;
if(type == 'moon') this.ogl._fleet.updateLimiter();
else if(type == 'jumpgate') this.ogl._jumpgate.updateLimiter();
}, 200);
}});
if(type == 'jumpgate' && (key == 'metal' || key == 'crystal' || key == 'deut' || key == 'food'))
{
input.classList.add('ogl_disabled');
input.value = 0;
}
Util.formatInput(input);
}
}
});
});
return container;
}
openKeyboardActions()
{
const container = Util.addDom('div', {class:'ogl_keyboardActions'});
const changes = {};
Util.addDom('h2', { parent:container, child:this.ogl._lang.find('keyboardActions') });
Object.entries(this.ogl.db.options.keyboardActions).forEach(key =>
{
const label = Util.addDom('label', { parent:container, child:`${this.ogl._lang.find(key[0])}` });
const input = Util.addDom('input', { maxlength:'1', type:'text', value:key[1], parent:label,
onclick:() =>
{
input.value = '';
input.select();
},
onblur:() =>
{
if(input.value == '') input.value = key[1];
},
onkeyup:event =>
{
if(event.key.toLowerCase() == 'enter') return;
changes[key[0]] = event.key.toLowerCase();
input.value = event.key.toLowerCase();
//changes[key[0]] = input.value;
}});
if(key[0] == 'fleetResourcesSplit')
{
input.classList.add('ogl_disabled');
input.disabled = true;
}
});
Util.addDom('button', { parent:container, class:'ogl_button', child:'save', onclick:() =>
{
Object.entries(changes).forEach(key =>
{
this.ogl.db.options.keyboardActions[key[0]] = changes[key[0]];
window.location.reload();
});
}});
return container;
}
openExpeditionFiller()
{
const container = Util.addDom('div', {class:'ogl_expeditionFiller'});
Util.addDom('h2', { parent:container, child:this.ogl._lang.find('expeditionBigShips') });
[204, 205, 206, 207, 215, 211, 213, 218].forEach(shipID =>
{
const item = Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, parent:container, onclick:() =>
{
if(this.ogl.db.options.expeditionBigShips.indexOf(shipID) > -1)
{
this.ogl.db.options.expeditionBigShips = this.ogl.db.options.expeditionBigShips.filter(a => a !== shipID);
item.classList.remove('ogl_active');
}
else
{
this.ogl.db.options.expeditionBigShips.push(shipID);
item.classList.add('ogl_active');
}
}});
if(this.ogl.db.options.expeditionBigShips.indexOf(shipID) > -1) item.classList.add('ogl_active');
});
return container;
}
openDataManager()
{
const container = Util.addDom('div', {class:'ogl_manageData'});
Util.addDom('h2', { parent:container, child:this.ogl._lang.find('manageData') });
const grid = Util.addDom('div', { class:'ogl_grid', parent:container });
// import data
Util.addDom('label', { class:'ogl_button', for:'ogl_import', child:'<i class="material-icons">file_open</i>Import all data', parent:grid, onclick:() => this.lastImportButton = 'all' });
Util.addDom('label', { class:'ogl_button', for:'ogl_import', child:'<i class="material-icons">monitoring</i>Import stats', parent:grid, onclick:() => this.lastImportButton = 'stats' });
Util.addDom('input', { id:'ogl_import', class:'ogl_hidden', accept:"application/JSON", type:'file', parent:grid, onchange:e =>
{
setTimeout(() => this.ogl.importData(e.target, this.lastImportButton), 200);
}});
// export
Util.addDom('a', { class:'ogl_button', download:`oglight_${this.ogl.server.name}_${this.ogl.server.lang}_${serverTime.getTime()}`, child:'<i class="material-icons">file_export</i>Export data', parent:grid, href:URL.createObjectURL(new Blob([JSON.stringify(this.ogl.db)], {type: 'application/json'})) });
const dangerZone = Util.addDom('fieldset', { class:'ogl_grid ogl_dangerZone', parent:grid, child:'<legend>Danger zone</legend>' });
// stats
Util.addDom('div', { class:'ogl_button', child:'<i class="material-icons">monitoring</i>' + this.ogl._lang.find('resetStats'), parent:dangerZone, onclick:() =>
{
if(confirm(this.ogl._lang.find('resetStatsLong')))
{
this.ogl.cache.raids = {};
this.ogl.db.stats = {};
window.location.reload();
this.ogl.db.initialTime = Date.now();
}
}});
// tagged
Util.addDom('div', { class:'ogl_button', child:'<i class="material-icons">stroke_full</i>' + this.ogl._lang.find('resetTaggedPlanets'), parent:dangerZone, onclick:() =>
{
if(confirm(this.ogl._lang.find('resetTaggedPlanetsLong')))
{
this.ogl.db.tdb = {};
this.ogl.db.quickRaidList = [];
window.location.reload();
}
}});
// pinned
Util.addDom('div', { class:'ogl_button', child:'<i class="material-icons">keep</i>' + this.ogl._lang.find('resetPinnedPlayers'), parent:dangerZone, onclick:() =>
{
if(confirm(this.ogl._lang.find('resetPinnedPlayersLong')))
{
this.ogl.db.lastStatusUpdate = 0;
this.ogl.db.lastGlobalScoreUpdate = 0;
this.ogl.db.pdb = {};
this.ogl.db.udb = {};
this.ogl.db.lastPinnedList = [];
this.ogl.db.quickRaidList = [];
window.location.reload();
}
}});
// all
Util.addDom('div', { class:'ogl_button', child:'<i class="material-icons">database</i>' + this.ogl._lang.find('resetAll'), parent:dangerZone, onclick:() =>
{
if(confirm(this.ogl._lang.find('resetAllLong')))
{
this.ogl.cache = {};
this.ogl.db = {};
window.location.reload();
this.ogl.db.initialTime = Date.now();
}
}});
return container;
}
groupPlanets()
{
let lastCoords = 0;
let group = 1;
document.querySelectorAll('.smallplanet').forEach(planet =>
{
let newCoords = Util.coordsToID(planet.querySelector('.planet-koords').innerText).slice(0, -3);
if(lastCoords === newCoords) planet.setAttribute('data-group', group);
else if(planet.previousElementSibling?.getAttribute('data-group')) group++;
lastCoords = newCoords;
});
}
checkImportExport()
{
if((this.ogl.db.nextImportExport || 0) < serverTime.getTime())
{
document.querySelector('.menubutton[href*=traderOverview]').classList.add('ogl_active');
}
window.addEventListener('beforeunload', () =>
{
let textTarget = document.querySelector('.bargain_text');
let button = document.querySelector('.import_bargain.hidden');
if(textTarget && button)
{
let today = new Date(serverTime.getTime());
let tomorow = new Date(serverTime.getTime() + 86400000);
if(textTarget.innerText.match(/\d+/g))
{
this.ogl.db.nextImportExport = new Date(today.getFullYear(), today.getMonth(), today.getDate(), textTarget.innerText.match(/\d+/g)[0], 0, 0).getTime();
}
else
{
this.ogl.db.nextImportExport = new Date(tomorow.getFullYear(), tomorow.getMonth(), tomorow.getDate(), 0, 0, 1).getTime();
}
this.ogl.save();
}
else if(textTarget && textTarget.innerText == '')
{
this.ogl.db.nextImportExport = serverTime.getTime();
this.ogl.save();
}
});
}
turnIntoPlayerLink(id, dom, name, status)
{
if(!dom.closest('.ogl_spyLine'))
{
dom.setAttribute('title', 'loading...');
dom.classList.add('tooltipUpdate');
dom.classList.add('tooltipRight');
dom.classList.add('tooltipClose');
}
if(status || this.ogl.db.udb?.[id]?.status)
{
dom.className = dom.className.replaceAll(/status_abbr_[a-zA-Z]+/g, '');
const playerStatus = status || this.ogl.db.udb?.[id]?.status || 'n';
const statusObj = this.ogl.playerStatus.find(e => e.defaultTag == playerStatus);
if(statusObj.serverTag != 'HONORABLE') dom.setAttribute('data-status-tag', statusObj.serverTag);
dom.classList.add(statusObj.class);
}
dom.addEventListener('click', event =>
{
if(!dom.closest('.ogl_spyLine'))
{
if(id == this.ogl.account.id || event.ctrlKey) return;
event.preventDefault();
this.ogl._topbar.openPinnedDetail(id);
}
});
dom.addEventListener('tooltip', () =>
{
const loading = Util.addDom('div', { child:'<div class="ogl_loading"></div>' });
dom._tippy.setContent(loading);
this.ogl._fetch.fetchPlayerAPI(id, name, () =>
{
setTimeout(() =>
{
dom._tippy.setContent(this.getPlayerTooltip(id));
if(document.querySelector('.ogl_pinDetail') && this.ogl.db.currentSide == id) // current pin
{
this.ogl._topbar.openPinnedDetail(id);
}
}, 100);
});
});
}
getPlayerTooltip(id)
{
const player = this.ogl.db.udb[id];
const page = Math.ceil(player.score.globalRanking / 100);
const status = this.ogl.playerStatus.find(e => e.defaultTag == player.status)?.class || 'status_abbr_active';
const container = Util.addDom('div',
{
class:'ogl_playerData' ,
child:`
<h1 class="${status}">${player.name} <a href="https://${window.location.host}/game/index.php?page=highscore&site=${page}&searchRelId=${id}">#${player.score.globalRanking}</a></h1>
<div class="ogl_grid">
<div class="ogl_tagSelector material-icons"></div>
<div class="ogl_leftSide">
<div class="ogl_actions"></div>
<div class="ogl_score">
<div class="ogl_line"><i class="material-icons">crown</i><div>${Util.formatNumber(player.score.global)}</div></div>
<div class="ogl_line"><i class="material-icons">diamond</i><div>${Util.formatNumber(player.score.economy)}</div></div>
<div class="ogl_line"><i class="material-icons">science</i><div>${Util.formatNumber(player.score.research)}</div></div>
<div class="ogl_line"><i class="material-icons">genetics</i><div>${Util.formatNumber(player.score.lifeform)}</div></div>
<div class="ogl_line"><i class="material-icons">rocket_launch</i><div>${Util.formatNumber(Util.getPlayerScoreFD(player.score, 'fleet'))}</div></div>
<div class="ogl_line"><i class="material-icons">security</i><div>${Util.formatNumber(Util.getPlayerScoreFD(player.score, 'defense'))}</div></div>
<div class="ogl_line"><i class="material-icons">schedule</i><div>${new Date(player.api).toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})}</div></div>
</div>
</div>
<div class="ogl_planetStalk"></div>
</div>`
});
// write
const writeIcon = Util.addDom('div', { child:'edit', class:'material-icons ogl_button', parent:container.querySelector('.ogl_actions'), onclick:() =>
{
if(!this.ogl.account.chatEnabled)
{
window.location.href = `https://${window.location.host}/game/index.php?page=chat&playerId=${player.uid}`;
}
}});
if(this.ogl.account.chatEnabled)
{
writeIcon.classList.add('js_openChat');
writeIcon.setAttribute('data-playerId', player.uid);
}
// buddy
Util.addDom('a', { child:'person_add', class:'material-icons ogl_button overlay', parent:container.querySelector('.ogl_actions'), href:`https://${window.location.host}/game/index.php?page=ingame&component=buddies&action=7&id=${player.uid}&ajax=1`, onclick:() =>
{
tippy.hideAll();
}});
// ignore
Util.addDom('div', { child:'block', class:'material-icons ogl_button', parent:container.querySelector('.ogl_actions'), onclick:() =>
{
window.location.href = `https://${window.location.host}/game/index.php?page=ignorelist&action=1&id=${player.uid}`;
}});
// mmorpgstat
Util.addDom('div', { child:'query_stats', class:'material-icons ogl_button', parent:container.querySelector('.ogl_actions'), onclick:() =>
{
window.open(Util.genMmorpgstatLink(this.ogl, player.uid), '_blank');
}});
if(id != this.ogl.account.id)
{
// pin to right
Util.addDom('div', { child:'arrow_forward', class:'material-icons ogl_button', parent:container.querySelector('.ogl_actions'), onclick:() =>
{
this.ogl._topbar.openPinnedDetail(player.uid);
}});
}
const planetList = container.querySelector('.ogl_planetStalk');
let lastCoords = 0;
let group = 1;
player.planets.sort((a, b) => Util.coordsToID(a) - Util.coordsToID(b)).forEach((planet, index) =>
{
let coords = planet.split(':');
let div = Util.addDom('div',
{
parent:planetList,
child:`<div>${index+1}</div><div data-galaxy="${coords[0]}:${coords[1]}">${planet}</div>`
});
let newCoords = Util.coordsToID(coords).slice(0, -3);
if(lastCoords === newCoords) div.setAttribute('data-group', group);
else if(div.previousElementSibling?.getAttribute('data-group')) group++;
lastCoords = newCoords;
if(this.ogl.db.pdb[planet]?.home) div.classList.add('ogl_home');
if(unsafeWindow['galaxy'] == coords[0] && unsafeWindow['system'] == coords[1]) div.querySelector('[data-galaxy]').classList.add('ogl_active');
this.addSpyIcons(div, coords);
this.addTagButton(div, coords, true);
});
if(player.uid != this.ogl.account.id)
{
const tagSelector = container.querySelector('.ogl_tagSelector');
Object.keys(this.ogl.db.tags).forEach(tag =>
{
Util.addDom('div', { parent:tagSelector, 'data-tag':tag, onclick:() =>
{
player.planets.forEach(planet =>
{
let raw = Util.coordsToID(planet.split(':'));
if(tag != 'none')
{
this.ogl.db.tdb[raw] = { tag:tag };
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.setAttribute('data-tag', tag));
}
else if(this.ogl.db.tdb[raw])
{
delete this.ogl.db.tdb[raw];
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.removeAttribute('data-tag'));
}
});
}});
});
}
return container;
}
addPinButton(element, id)
{
const player = this.ogl.db.udb[id];
const div = Util.addDom('div', { title:'loading...', class:'ogl_flagPicker material-icons tooltipLeft tooltipClick tooltipClose tooltipUpdate', 'data-uid':id, parent:element, ontooltip:event =>
{
div._tippy.setContent(tooltip);
}, onclick:event =>
{
if(event.shiftKey)
{
event.preventDefault();
if(this.ogl.db.lastPinUsed == 'none' && this.ogl.db.udb[id])
{
delete this.ogl.db.udb[id].pin;
document.querySelectorAll(`.ogl_flagPicker[data-uid="${id}"]`).forEach(e =>
{
e.removeAttribute('data-flag');
e.innerText = '';
});
}
else
{
this.ogl.db.udb[id] = this.ogl.db.udb[id] || this.ogl.createPlayer(id);
this.ogl.db.udb[id].pin = this.ogl.db.lastPinUsed;
document.querySelectorAll(`.ogl_flagPicker[data-uid="${id}"]`).forEach(e =>
{
e.setAttribute('data-flag', this.ogl.db.lastPinUsed);
});
}
}
}});
const tooltip = Util.addDom('div', { class:'ogl_flagSelector material-icons' });
this.ogl.flagsList.forEach(pin =>
{
if(pin == 'ptre' && !this.ogl.ptreKey) return;
const icon = Util.addDom('div', { 'data-flag':pin, parent:tooltip, onclick:() =>
{
if(pin == 'none' && this.ogl.db.udb[id])
{
delete this.ogl.db.udb[id].pin;
document.querySelectorAll(`.ogl_flagPicker[data-uid="${id}"]`).forEach(e =>
{
e.removeAttribute('data-flag');
e.innerText = '';
});
}
else
{
this.ogl.db.udb[id] = this.ogl.db.udb[id] || this.ogl.createPlayer(id);
this.ogl.db.udb[id].pin = pin;
document.querySelectorAll(`.ogl_flagPicker[data-uid="${id}"]`).forEach(e =>
{
e.setAttribute('data-flag', pin);
});
}
this.ogl.db.lastPinUsed = pin;
if(pin != 'none') this.ogl._topbar.openPinnedDetail(id);
tippy.hideAll();
}});
});
if(player?.pin)
{
div.setAttribute('data-flag', player.pin);
}
}
addTagButton(element, coords, disabled)
{
const raw = Util.coordsToID(coords);
const position = this.ogl.db.tdb[raw];
const div = Util.addDom('div', { title:'loading...', class:'ogl_tagPicker material-icons tooltipLeft tooltipClick tooltipClose tooltipUpdate', 'data-raw':raw, parent:element, ontooltip:event =>
{
if(!disabled)
{
div._tippy.setContent(tooltip);
}
},
onclick:event =>
{
if(event.shiftKey && !disabled)
{
if(this.ogl.db.lastTagUsed == 'none' && this.ogl.db.tdb[raw])
{
delete this.ogl.db.tdb[raw];
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.removeAttribute('data-tag'));
}
else
{
this.ogl.db.tdb[raw] = this.ogl.db.tdb[raw] || {};
this.ogl.db.tdb[raw].tag = this.ogl.db.lastTagUsed;
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.setAttribute('data-tag', this.ogl.db.lastTagUsed));
}
}
}});
const tooltip = Util.addDom('div', { class:'ogl_tagSelector material-icons' });
Object.keys(this.ogl.db.tags).forEach(tag =>
{
Util.addDom('div', { 'data-tag':tag, parent:tooltip, onclick:() =>
{
if(tag == 'none' && this.ogl.db.tdb[raw])
{
delete this.ogl.db.tdb[raw];
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.removeAttribute('data-tag'));
}
else
{
this.ogl.db.tdb[raw] = this.ogl.db.tdb[raw] || {};
this.ogl.db.tdb[raw].tag = tag;
document.querySelectorAll(`.ogl_tagPicker[data-raw="${raw}"]`).forEach(e => e.setAttribute('data-tag', tag));
}
this.ogl.db.lastTagUsed = tag;
tippy.hideAll();
}});
});
if(position?.tag)
{
div.setAttribute('data-tag', position.tag);
}
}
addSpyIcons(parent, coords, uniqueType, displayActivity)
{
coords = typeof coords == typeof '' ? coords = coords.split(':') : coords;
if(uniqueType == 'planet' || !uniqueType)
{
const planetIcon = Util.addDom('div',
{
class:'material-icons ogl_spyIcon',
'data-spy-coords':`${coords[0]}:${coords[1]}:${coords[2]}:1`, child:'language', parent:parent,
onclick:e => window.location.href = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=1`,
//onclick:e => this.ogl._notification.addToQueue(this.ogl._lang.find('notifyNoProbe'), false, true)
});
const lastPlanetSpy = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.spy?.[0] || 0;
if(serverTime.getTime() - lastPlanetSpy < this.ogl.db.options.spyIndicatorDelay)
{
planetIcon.setAttribute('data-spy', 'recent');
planetIcon.setAttribute('title', 'recently spied');
}
if(displayActivity)
{
const activity = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.acti || [];
const isRecent = serverTime.getTime() - activity[2] < 3600000;
const activityDom = Util.addDom('span', { parent:planetIcon, child:isRecent ? activity[0] : '?' });
(activity[0] == '*' && isRecent) ? activityDom.classList.add('ogl_danger') : (activity[0] == 60 && isRecent) ? activityDom.classList.add('ogl_ok') : activityDom.classList.add('ogl_warning');
}
if(Object.values(ogl.cache.movements).flat().find(e => e.to.coords == `${coords[0]}:${coords[1]}:${coords[2]}` && !e.to.isMoon && e.mission == 1 && !e.isBack))
{
planetIcon.classList.add('ogl_attacked');
}
}
if(uniqueType == 'moon' || (!uniqueType && this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid))
{// onclick:e => this.ogl._fleet.addToSpyQueue(6, coords[0], coords[1], coords[2], 3)
const moonIcon = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid > 0 ? Util.addDom('div',
{
class:'material-icons ogl_spyIcon',
'data-spy-coords':`${coords[0]}:${coords[1]}:${coords[2]}:3`,
child:'bedtime',
parent:parent,
onclick:e => window.location.href = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=3`
}) : Util.addDom('div', { parent:parent, class:'ogl_invisible' });
const lastMoontSpy = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.spy?.[1] || 0;
if(serverTime.getTime() - lastMoontSpy < this.ogl.db.options.spyIndicatorDelay)
{
moonIcon.setAttribute('data-spy', 'recent');
moonIcon.setAttribute('title', 'recently spied');
}
if(displayActivity && this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid > -1)
{
const activity = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.acti || [];
const isRecent = serverTime.getTime() - activity[2] < 3600000;
const activityDom = Util.addDom('span', { parent:moonIcon, child:isRecent ? activity[1] : '?' });
(activity[1] == '*' && isRecent) ? activityDom.classList.add('ogl_danger') : (activity[1] == 60 && isRecent) ? activityDom.classList.add('ogl_ok') : activityDom.classList.add('ogl_warning');
}
if(Object.values(ogl.cache.movements).flat().find(e => e.to.coords == `${coords[0]}:${coords[1]}:${coords[2]}` && e.to.isMoon && e.mission == 1 && !e.isBack))
{
moonIcon.classList.add('ogl_attacked');
}
}
if(!uniqueType && ! this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid)
{
Util.addDom('div', { parent:parent });
}
}
displayResourcesRecap()
{
const resources = {};
resources.total = { metal:0, crystal:0, deut:0, msu:0 };
resources.prod = { metal:0, crystal:0, deut:0, msu:0 };
resources.fly = { metal:0, crystal:0, deut:0 };
resources.ground = { metal:0, crystal:0, deut:0 };
resources.todo = { metal:0, crystal:0, deut:0 };
Object.values(this.ogl._dom.planet).forEach(planet =>
{
const id = planet._ogl.id;
const planetObj = this.ogl.db.myPlanets[id];
if(!planetObj) return;
['metal', 'crystal', 'deut'].forEach(resourceName =>
{
resources.total[resourceName] += this.ogl.db.myPlanets[id]?.[resourceName] || 0;
resources.ground[resourceName] += this.ogl.db.myPlanets[id]?.[resourceName] || 0;
const prod = planet._ogl.type == 'planet' ? this.ogl.db.myPlanets[id]?.['prod'+resourceName] : 0;
resources.prod[resourceName] += prod || 0;
});
Object.values(this.ogl.db.myPlanets[id]?.todolist || {}).forEach(entry =>
{
Object.values(entry || {}).forEach(todo =>
{
if(!todo.cost) return;
resources.todo.metal += todo.cost.metal;
resources.todo.crystal += todo.cost.crystal;
resources.todo.deut += todo.cost.deut;
});
});
});
Object.entries(this.ogl.cache?.movements || {}).forEach(entry =>
{
entry[1].forEach(line =>
{
['metal', 'crystal', 'deut'].forEach(resourceName =>
{
resources.total[resourceName] += line[resourceName] || 0;
resources.fly[resourceName] += line[resourceName] || 0;
});
});
});
const msuValue = this.ogl.db.options.msu;
resources.total.msu = Util.getMSU(resources.total.metal, resources.total.crystal, resources.total.deut, msuValue);
resources.prod.metal = Math.round((resources.prod.metal || 0) * 3600 * 24);
resources.prod.crystal = Math.round((resources.prod.crystal || 0) * 3600 * 24);
resources.prod.deut = Math.round((resources.prod.deut || 0) * 3600 * 24);
resources.prod.msu = Util.getMSU(resources.prod.metal, resources.prod.crystal, resources.prod.deut, msuValue);
this.ogl._dom.updateRecap(resources);
if(!this.recapReady)
{
this.recapReady = true;
this.ogl._dom.recap.addEventListener('click', () =>
{
const container = Util.addDom('div', { class:'ogl_resourcesDetail' });
container.innerHTML =
`
<div>
<div class="ogl_group">
<h3 class="material-icons">handyman</h3>
<h4>Construction</h4>
</div>
<div class="ogl_metal">+${Util.formatToUnits(resources.prod.metal)}</div>
<div class="ogl_crystal">+${Util.formatToUnits(resources.prod.crystal)}</div>
<div class="ogl_deut">+${Util.formatToUnits(resources.prod.deut)}</div>
</div>
<div>
<div class="ogl_group">
<h3 class="material-icons">lists</h3>
<h4>Todolist</h4>
</div>
<div class="ogl_metal ogl_todoDays">${Util.formatToUnits(resources.todo.metal)} <span>${Math.ceil(Math.max(0, resources.todo.metal - resources.total.metal) / resources.prod.metal)}${LocalizationStrings.timeunits.short.day}</span></div>
<div class="ogl_crystal ogl_todoDays">${Util.formatToUnits(resources.todo.crystal)} <span>${Math.ceil(Math.max(0, resources.todo.crystal - resources.total.crystal) / resources.prod.crystal)}${LocalizationStrings.timeunits.short.day}</span></div>
<div class="ogl_deut ogl_todoDays">${Util.formatToUnits(resources.todo.deut)} <span>${Math.ceil(Math.max(0, resources.todo.deut - resources.total.deut) / resources.prod.deut)}${LocalizationStrings.timeunits.short.day}</span></div>
</div>
<div>
<div class="ogl_group">
<h3 class="material-icons">globe_uk</h3>
<h4>Planet / moon</h4>
</div>
<div class="ogl_metal">${Util.formatToUnits(resources.ground.metal)}</div>
<div class="ogl_crystal">${Util.formatToUnits(resources.ground.crystal)}</div>
<div class="ogl_deut">${Util.formatToUnits(resources.ground.deut)}</div>
</div>
<div>
<div class="ogl_group">
<h3 class="material-icons">send</h3>
<h4>Flying</h4>
</div>
<div class="ogl_metal">${Util.formatToUnits(resources.fly.metal)}</div>
<div class="ogl_crystal">${Util.formatToUnits(resources.fly.crystal)}</div>
<div class="ogl_deut">${Util.formatToUnits(resources.fly.deut)}</div>
</div>
<div>
<div class="ogl_group">
<h3 class="material-icons">functions</h3>
<h4>Total</h4>
</div>
<div class="ogl_metal">${Util.formatToUnits(resources.total.metal)}</div>
<div class="ogl_crystal">${Util.formatToUnits(resources.total.crystal)}</div>
<div class="ogl_deut">${Util.formatToUnits(resources.total.deut)}</div>
</div>
`;
this.ogl._popup.open(container);
});
}
}
static hasVisibleBottomScrollBar()
{
const scrollTop = document.documentElement.scrollTop;
const clientHeight = document.documentElement.clientHeight;
const scrollHeight = document.documentElement.scrollHeight;
const isScrolledToBottom = (scrollTop + clientHeight) >= (scrollHeight - 1);
const hasHorizontalScrollbar = Math.max(
document.body.scrollWidth,
document.documentElement.scrollWidth
) > window.innerWidth;
return hasHorizontalScrollbar && isScrolledToBottom;
}
}
class TopbarManager extends Manager
{
load(reloaded)
{
this.ogl.db.lastAccountView = this.ogl.db.lastAccountView || 'summary';
this.topbar = Util.addDom('div', {class:'ogl_topbar', prepend:document.querySelector('#planetList')});
Util.addDom('i', {class:'material-icons tooltip', child:'conversion_path', title:this.ogl._lang.find('collectResources'),parent:this.topbar, onclick:e =>
{
this.ogl.db.harvestCoords = false;
document.body.classList.toggle('ogl_destinationPicker');
document.body.classList.toggle('ogl_initHarvest');
}});
Util.addDom('i', { class:'material-icons tooltip', child:'account_balance', parent:this.topbar, title:this.ogl._lang.find('accountSummary'), onclick:() =>
{
this.ogl._account.openSummary(true);
}});
//Util.addDom('i', { class:'material-icons tooltip', child:'clock_loader_60', parent:this.topbar, title:this.ogl._lang.find('stats'), onclick:() => this.openStats() });
Util.addDom('i', { class:'material-icons tooltip', child:'stroke_full', parent:this.topbar, title:this.ogl._lang.find('taggedPlanets'), onclick:() => this.openTagged(true) });
Util.addDom('i', { class:'material-icons tooltip', child:'keep', parent:this.topbar, title:this.ogl._lang.find('pinnedPlayers'), onclick:() => this.openPinned(true) });
Util.addDom('i', { class:'material-icons tooltip', child:'settings', parent:this.topbar, title:this.ogl._lang.find('oglSettings'), onclick:() => this.openSettings(true) });
Util.addDom('a', { parent:this.topbar, class:'material-icons tooltip', child:'favorite', title:this.ogl._lang.find('coffee'), target:'_blank', href:'https://ko-fi.com/O4O22XV69' });
this.syncBtn = Util.addDom('i', {class:'material-icons tooltip', child:'directory_sync', title:this.ogl._lang.find('syncEmpire'), parent:this.topbar, onclick:() =>
{
this.ogl._fetch.fetchMainData(false, true);
}});
if(!reloaded)
{
if(!isNaN(this.ogl.db.currentSide)) this.openPinnedDetail(this.ogl.db.currentSide);
else if(this.ogl.db.currentSide == 'settings') this.openSettings();
else if(this.ogl.db.currentSide == 'pinned') this.openPinned();
else if(this.ogl.db.currentSide == 'tagged') this.openTagged();
}
Util.addDom('button', { class:'ogl_button', child:this.ogl._lang.find('siblingPlanetMoon'), parent:this.topbar, onclick:() =>
{
window.location.href = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&oglmode=2`;
}});
}
openCards(type)
{
type = type || 'planet';
this.ogl.db.lastAccountView = type;
const container = Util.addDom('div', { class:'ogl_empireCards', 'data-type':type });
const icon = Util.addDom('div', { class:`ogl_empireType`, parent:container });
const grid = Util.addDom('div', { class:'ogl_grid', parent:container });
const lineDoms = {};
const cumul = {};
const typeLen = Object.values(this.ogl._dom.planet).filter(e => e._ogl.type == type)?.length || 0;
if(Object.values(this.ogl._fetch.fetchedError).indexOf(1) >= 0)
{
Util.addDom('div', { class:'ogl_outdated ogl_danger tooltip', title:'Warning : fetch has failed, data may be outdated', parent:container, child:'<span class="material-icons">schedule</span>Outdated' });
}
Util.addDom('div', { class:`material-icons`, onclick:() => this.openAccount(), parent:icon, child:'diamond' });
['planet', 'moon'].forEach(typeName =>
{
Util.addDom('div', { class:`ogl_${typeName}Icon`, onclick:() => this.openCards(typeName), parent:icon });
});
lineDoms.icons = Util.addDom('div', { parent:grid, class:`ogl_icon ogl_iconsList`, child:'<div class="ogl_invisible"></div>' });
lineDoms.planets = Util.addDom('div', { parent:grid, class:`ogl_icon ogl_coordsList`, child:'<div class="ogl_invisible"></div>' });
['metal', 'crystal', 'deut'].forEach(resource =>
{
lineDoms[resource] = Util.addDom('div', { class:`ogl_icon ogl_${resource}`, parent:grid });
});
[...this.ogl.shipsList, '217'].forEach(shipID =>
{
lineDoms[shipID] = Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, parent:grid });
});
Object.values(this.ogl._dom.planet).filter(e => e._ogl.type == type).sort((a, b) => Util.coordsToID(a._ogl.coords) - Util.coordsToID(b._ogl.coords)).forEach((planet, index) =>
{
const planetObj = this.ogl.db.myPlanets[planet._ogl.id];
if(!planetObj) return;
const pic = type == 'moon' ? planet.querySelector('img') : planet.querySelector('.planetPic');
Util.addDom('img',
{
parent:lineDoms.icons,
src:pic.getAttribute('src')
});
if(index == typeLen-1) Util.addDom('div', { class:'ogl_empireTotal', parent:lineDoms.icons, child:typeLen });
Util.addDom('div', { parent:lineDoms.planets, child:planetObj.coords, 'data-galaxy':planetObj.coords });
if(index == typeLen-1) Util.addDom('div', { class:'ogl_empireTotal', parent:lineDoms.planets, child:'total' });
['metal', 'crystal', 'deut'].forEach(resource =>
{
const total = planetObj[resource] || 0;
Util.addDom('div', { 'data-value':total, child:Util.formatToUnits(total, 0), parent:lineDoms[resource] });
cumul[resource] = (cumul[resource] || 0) + total;
if(index == typeLen-1)
{
Util.addDom('div', { class:'ogl_empireTotal', 'data-value':cumul[resource], child:Util.formatToUnits(cumul[resource], 0), parent:lineDoms[resource] });
}
});
[...this.ogl.shipsList, '217'].forEach(shipID =>
{
const total = planetObj[shipID] || 0;
Util.addDom('div', { 'data-value':total, child:Util.formatToUnits(total, 0), parent:lineDoms[shipID] });
cumul[shipID] = (cumul[shipID] || 0) + total;
if(index == typeLen-1)
{
Util.addDom('div', { class:'ogl_empireTotal', 'data-value':cumul[shipID], child:Util.formatToUnits(cumul[shipID], 0), parent:lineDoms[shipID] });
}
});
});
this.ogl._popup.open(container, true);
}
openAccount()
{
const container = Util.addDom('div', {class:'ogl_empire'});
this.ogl.db.lastAccountView = 'summary';
if(Object.values(this.ogl._fetch.fetchedError).indexOf(1) >= 0)
{
Util.addDom('div', { class:'ogl_outdated ogl_danger tooltip', title:'Warning : fetch has failed, data may be outdated', parent:container, child:'<span class="material-icons">schedule</span>Outdated' });
}
const icon = Util.addDom('div', { class:`ogl_empireType`, parent:container });
const grid = Util.addDom('div', { class:'ogl_grid', parent:container });
Util.addDom('div', { class:`material-icons`, onclick:() => this.openAccount(), parent:icon, child:'diamond' });
['planet', 'moon'].forEach(typeName =>
{
Util.addDom('div', { class:`ogl_${typeName}Icon`, onclick:() => this.openCards(typeName), parent:icon });
});
const count = document.querySelectorAll('.smallplanet').length;
const stack = {};
stack.fieldUsed = 0;
stack.fieldMax = 0;
stack.fieldLeft = 0;
stack.temperature = 0;
stack.metal = 0;
stack.crystal = 0;
stack.deut = 0;
stack.prodmetal = 0;
stack.prodcrystal = 0;
stack.proddeut = 0;
// top
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_invisible', parent:grid});
Util.addDom('div', {class:'ogl_icon ogl_metal', parent:grid});
Util.addDom('div', {class:'ogl_icon ogl_crystal', parent:grid});
Util.addDom('div', {class:'ogl_icon ogl_deut', parent:grid});
Util.addDom('div', {child:'Coords', parent:grid});
Util.addDom('div', {child:'P', parent:grid});
Util.addDom('div', {child:'M', parent:grid});
Util.addDom('div', {child:'Name', parent:grid});
Util.addDom('div', {child:'Fields', parent:grid});
Util.addDom('div', {child:'T°c', parent:grid});
Util.addDom('div', {child:'LF', parent:grid});
let metalStack = Util.addDom('div',
{
class:'ogl_metal',
parent:grid
});
let crystalStack = Util.addDom('div',
{
class:'ogl_crystal',
parent:grid
});
let deutStack = Util.addDom('div',
{
class:'ogl_deut',
parent:grid
});
document.querySelectorAll('.smallplanet').forEach(line =>
{
const id = line.getAttribute('id').replace('planet-', '');
const planet = this.ogl.db.myPlanets[id];
const moon = this.ogl.db.myPlanets[planet.moonID];
const name = line.querySelector('.planet-name').innerText;
// coords
let coordDiv = Util.addDom('div',
{
parent:grid,
'data-galaxy':planet.coords,
child:planet.coords
});
if(line.getAttribute('data-group')) coordDiv.setAttribute('data-group', line.getAttribute('data-group'));
// planet picture
Util.addDom('a',
{
parent:grid,
href:line.querySelector('.planetlink').getAttribute('href'),
child:Util.addDom('img',
{
src:line.querySelector('.planetPic').getAttribute('src')
})
});
// moon picture
if(line.querySelector('.moonlink'))
{
Util.addDom('a',
{
parent:grid,
href:line.querySelector('.moonlink').getAttribute('href'),
child:Util.addDom('img',
{
src:line.querySelector('.moonlink img').getAttribute('src')
})
});
}
else
{
Util.addDom('div', { class:'ogl_invisible', parent:grid });
}
// planet name
Util.addDom('div',
{
parent:grid,
child:name
});
// planet fields
Util.addDom('div',
{
parent:grid,
child:`${planet.fieldUsed}/${planet.fieldMax} (<span>${planet.fieldMax-planet.fieldUsed}</span>)`
});
stack.fieldUsed += planet.fieldUsed;
stack.fieldMax += planet.fieldMax;
stack.fieldLeft += (planet.fieldMax-planet.fieldUsed);
// °C
let temperature = Util.addDom('div',
{
parent:grid,
child:planet.temperature + 40 + '°C'
});
stack.temperature += (planet.temperature + 40);
if(planet.temperature >= 110) temperature.style.color = "#af644d"; // too hot
else if(planet.temperature>= 10) temperature.style.color = "#af9e4d"; // hot
else if(planet.temperature >= -40) temperature.style.color = "#4daf67"; // normal
else if(planet.temperature >= -140) temperature.style.color = "#4dafa6"; // cold
else temperature.style.color = "#4d79af"; // too cold
// lieform
Util.addDom('div',
{
class:`ogl_icon ogl_lifeform${planet.lifeform || 0}`,
parent:grid
});
// metal mine
let metal = Util.addDom('div',
{
class:'ogl_metal',
parent:grid,
child:`<strong>${planet[1]}</strong><small>+${Util.formatToUnits(Math.round((planet.prodmetal || 0) * 3600 * 24))}</small>`
});
if(planet.upgrades?.['baseBuilding']?.[0]?.name.trim() == this.ogl.db.serverData[1] && serverTime.getTime() < planet.upgrades?.['baseBuilding']?.[0]?.end) metal.querySelector('strong').innerHTML += `<span>${planet[1]+1}</span>`;
// crystal mine
let crystal = Util.addDom('div',
{
class:'ogl_crystal',
parent:grid,
child:`<strong>${planet[2]}</strong><small>+${Util.formatToUnits(Math.round((planet.prodcrystal || 0) * 3600 * 24))}</small>`
});
if(planet.upgrades?.['baseBuilding']?.[0]?.name.trim() == this.ogl.db.serverData[2] && serverTime.getTime() < planet.upgrades?.['baseBuilding']?.[0]?.end) crystal.querySelector('strong').innerHTML += `<span>${planet[2]+1}</span>`;
// deut mine
let deut = Util.addDom('div',
{
class:'ogl_deut',
parent:grid,
child:`<strong>${planet[3]}</strong><small>+${Util.formatToUnits(Math.round((planet.proddeut || 0) * 3600 * 24))}</small>`
});
stack.metal += planet[1];
stack.crystal += planet[2];
stack.deut += planet[3];
stack.prodmetal += planet.prodmetal || 0;
stack.prodcrystal += planet.prodcrystal || 0;
stack.proddeut += planet.proddeut || 0;
if(planet.upgrades?.['baseBuilding']?.[0]?.name.trim() == this.ogl.db.serverData[3] && serverTime.getTime() < planet.upgrades?.['baseBuilding']?.[0]?.end) deut.querySelector('strong').innerHTML += `<span>${planet[3]+1}</span>`;
});
metalStack.innerHTML = `<strong>${(stack.metal / count).toFixed(1)}</strong><small>+${Util.formatToUnits(Math.round((stack.prodmetal || 0) * 3600 * 24))}</small>`;
crystalStack.innerHTML = `<strong>${(stack.crystal / count).toFixed(1)}</strong><small>+${Util.formatToUnits(Math.round((stack.prodcrystal || 0) * 3600 * 24))}</small>`;
deutStack.innerHTML = `<strong>${(stack.deut / count).toFixed(1)}</strong><small>+${Util.formatToUnits(Math.round((stack.proddeut || 0) * 3600 * 24))}</small>`;
this.ogl._popup.open(container, true);
}
openStats()
{
Util.runAsync(() => this.ogl._stats.buildStats(false, false)).then(e => this.ogl._popup.open(e, true));
}
openSettings(buttonSource)
{
const container = Util.addDom('div', {class:'ogl_config', child:'<h2>Settings<i class="material-icons">settings</i></h2>'});
let subContainer;
let options =
[
'defaultShip', 'defaultMission', 'profileButton',
'resourceTreshold', 'msu', 'sim', 'converter', 'useClientTime', 'keyboardActions',
'showMenuResources', /*'tooltipDelay',*/ 'shortcutsOnRight', 'sidePanelOnLeft', 'disablePlanetTooltips', 'reduceLargeImages', 'colorblindMode', 'displayPlanetTimers',
'expeditionValue', 'expeditionRandomSystem', 'expeditionRedirect', 'expeditionBigShips',
'expeditionShipRatio', 'ignoreExpeShipsLoss', 'ignoreConsumption',
'displaySpyTable', 'autoCleanReports', 'autoCleanCounterSpies', 'boardTab', 'spyTableMSU', 'spyTableRules',
'ptreTeamKey', 'ptreLogs',
'manageData', 'debugMode',
];
options.forEach(opt =>
{
const isBoolean = typeof this.ogl.db.options[opt] === typeof true;
const isNumber = typeof this.ogl.db.options[opt] !== typeof [] && (typeof this.ogl.db.options[opt] === typeof 0 || Number(this.ogl.db.options[opt]));
//const isString = typeof this.ogl.db.options[opt] === typeof '';
if(!this.ogl.db.options[opt]) this.ogl.db.options[opt]
if(opt == 'defaultShip') subContainer = 'fleet';
else if(opt == 'resourceTreshold') subContainer = 'general';
else if(opt == 'showMenuResources') subContainer = 'interface';
else if(opt == 'expeditionValue') subContainer = 'expeditions';
else if(opt == 'expeditionShipRatio') subContainer = 'stats';
else if(opt == 'displaySpyTable') subContainer = 'messages';
else if(opt == 'ptreTeamKey') subContainer = 'PTRE';
else if(opt == 'manageData') subContainer = 'data';
let currentContainer;
if(!container.querySelector(`[data-container="${subContainer}"]`))
{
currentContainer = Util.addDom('div', { parent:container, 'data-container':subContainer });
if(this.ogl.db.configState[subContainer]) currentContainer.classList.add('ogl_active');
Util.addDom('h3', { parent:currentContainer, child:subContainer, onclick:() =>
{
if(currentContainer.classList.contains('ogl_active'))
{
currentContainer.classList.remove('ogl_active');
this.ogl.db.configState[currentContainer.getAttribute('data-container')] = false;
}
else
{
currentContainer.classList.add('ogl_active');
this.ogl.db.configState[currentContainer.getAttribute('data-container')] = true;
}
}});
}
else
{
currentContainer = container.querySelector(`[data-container="${subContainer}"]`);
}
const label = Util.addDom('label', { parent:currentContainer, 'data-label':`${this.ogl._lang.find(opt)}`, 'data-opt':opt });
const tooltip = this.ogl._lang.find(opt+'TT');
if(tooltip != 'TEXT_NOT_FOUND')
{
label.classList.add('tooltipLeft');
label.setAttribute('title', `<div class="ogl_settingsTooltip">${tooltip}</div>`);
}
if(opt == 'defaultShip')
{
this.ogl.fretShips.forEach(shipID =>
{
let div = Util.addDom('div', {parent:label, class:`ogl_icon ogl_${shipID}`, onclick:(event, element) =>
{
this.ogl.db.options.defaultShip = shipID;
label.querySelector('.ogl_active')?.classList.remove('ogl_active');
element.classList.add('ogl_active');
if(this.ogl.page == 'fleetdispatch')
{
document.querySelectorAll('#fleet1 .ogl_fav').forEach(e => e.classList.add('ogl_grayed'));
document.querySelector(`[data-technology="${this.ogl.db.options.defaultShip}"]`)?.classList.remove('ogl_grayed');
this.ogl._fleet.updateLimiter();
if(this.ogl.mode === 1 || this.ogl.mode === 2)
{
this.ogl.fretShips.forEach(shipID => fleetDispatcher.selectShip(shipID, 0));
fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, this.ogl._fleet.shipsForResources());
fleetDispatcher.selectMaxAll();
}
else if(this.ogl.mode === 3 && this.ogl.cache.toSend)
{
this.ogl.fretShips.forEach(shipID => fleetDispatcher.selectShip(shipID, 0));
this.ogl._fleet.prefillTodolistCargo();
}
}
}});
if(this.ogl.db.options.defaultShip == shipID) div.classList.add('ogl_active');
});
}
else if(opt == 'defaultMission')
{
[3, 4, 8, 1].forEach(missionID =>
{
let div = Util.addDom('div', {parent:label, class:`ogl_icon ogl_mission${missionID}`, onclick:(event, element) =>
{
this.ogl.db.options.defaultMission = missionID;
label.querySelector('.ogl_active')?.classList.remove('ogl_active');
element.classList.add('ogl_active');
}});
if(this.ogl.db.options.defaultMission == missionID) div.classList.add('ogl_active');
});
}
else if(opt == 'profileButton')
{
label.innerHTML = `<button class="material-icons">cancel_schedule_send</button>`;
label.querySelector('button').addEventListener('click', () =>
{
Util.runAsync(() => this.ogl._ui.openFleetProfile()).then(e => this.ogl._popup.open(e));
});
}
else if(opt == 'msu')
{
label.classList.add('tooltipLeft');
label.setAttribute('title', 'Format:<br>metal:crystal:deut');
const input = Util.addDom('input', { type:'text', placeholder:'m:c:d', value:this.ogl.db.options[opt], parent:label,
oninput:() =>
{
if(input.value && !/^[0-9]*[.]?[0-9]+:[0-9]*[.]?[0-9]+:[0-9]*[.]?[0-9]+$/.test(input.value))
{
input.classList.add('ogl_danger');
}
else
{
input.classList.remove('ogl_danger');
this.ogl.db.options[opt] = input.value.match(/^[0-9]*[.]?[0-9]+:[0-9]*[.]?[0-9]+:[0-9]*[.]?[0-9]+$/)[0];
}
}});
}
else if(opt == 'showMenuResources')
{
label.innerHTML = ``;
const select = Util.addDom('select', { parent:label, class:'dropdownInitialized', onchange:() =>
{
this.ogl.db.options[opt] = parseInt(select.value);
localStorage.setItem('ogl_menulayout', this.ogl.db.options[opt]);
document.body.setAttribute('data-menulayout', select.value);
}});
['All', 'Coords', 'Resources'].forEach((entry, index) =>
{
const selectOption = Util.addDom('option', { parent:select, child:entry, value:index });
if(this.ogl.db.options[opt] == index) selectOption.selected = true;
});
}
else if(isBoolean && opt != 'sim' && opt != 'expeditionValue')
{
if(opt == 'boardTab' && this.ogl.server.lang != 'fr') { label.remove(); return; }
const input = Util.addDom('input', { type:'checkbox', parent:label, onclick:() =>
{
this.ogl.db.options[opt] = !this.ogl.db.options[opt];
input.checked = this.ogl.db.options[opt];
if (opt == 'ignoreExpeShipsLoss' && this.ogl.db.options.displayMiniStats)
{
this.ogl._stats.showMiniRecap();
}
else if (opt == 'ignoreConsumption' && this.ogl.db.options.displayMiniStats)
{
this.ogl._stats.showMiniRecap();
}
else if(opt == 'displayPlanetTimers')
{
document.querySelector('#planetList').classList.toggle('ogl_alt')
}
else if(opt == 'reduceLargeImages')
{
localStorage.setItem('ogl_minipics', this.ogl.db.options[opt]);
document.body.setAttribute('data-minipics', this.ogl.db.options[opt]);
}
else if(opt == 'colorblindMode')
{
localStorage.setItem('ogl_colorblind', this.ogl.db.options[opt]);
document.body.setAttribute('data-colorblind', this.ogl.db.options[opt]);
}
else if(opt == 'displaySpyTable' && this.ogl._message?.spytable && this.ogl._message?.tabID == 20)
{
if(this.ogl.db.options[opt]) this.ogl._message.spytable.classList.remove('ogl_hidden');
else this.ogl._message.spytable.classList.add('ogl_hidden')
}
else if(opt == 'sidePanelOnLeft')
{
localStorage.setItem('ogl_sidepanelleft', this.ogl.db.options[opt]);
document.body.setAttribute('data-sidepanel', this.ogl.db.options[opt]);
}
else if(opt == 'spyTableMSU')
{
this.ogl._message.loadSpyTable();
this.ogl._message.spytable.querySelector('[data-filter="wave1"]').innerText = this.ogl.db.options.spyTableMSU ? 'MSU' : 'loot';
}
}});
if(this.ogl.db.options[opt]) input.checked = true;
}
else if(isNumber || opt == 'expeditionValue')
{
// fix old expeditionValue value "false"
if(opt == 'expeditionValue' && isNaN(this.ogl.db.options[opt]) && this.ogl.db.options[opt].indexOf('%') < 0) this.ogl.db.options[opt] = 0;
const txt = opt == 'expeditionValue' && this.ogl.db.options[opt] == 0 ? '' : this.ogl.db.options[opt];
const input = Util.addDom('input', { class:'ogl_inputCheck', type:'text', value:txt, parent:label, oninput:() =>
{
setTimeout(() =>
{
if(opt == 'expeditionShipRatio') // min
{
if(parseInt(input.value.replace(/\D/g, '')) < 0) input.value = 0;
else if(parseInt(input.value.replace(/\D/g, '')) > 100) input.value = 100;
}
let newValue;
if(input.getAttribute('data-allowPercent') == 'true' && input.value.toLowerCase().indexOf('%') >= 0)
{
newValue = (parseInt(input.value.replace(/\D/g, '')) || 0);
if(newValue) newValue += '%';
}
else
{
newValue = (parseInt(input.value.replace(/\D/g, '')) || 0)
}
this.ogl.db.options[opt] = newValue;
if(opt == 'expeditionShipRatio') this.ogl._stats.showMiniRecap();
}, 200);
}});
if(opt == 'expeditionValue')
{
input.setAttribute('data-allowPercent', true);
input.classList.add('ogl_placeholder');
input.setAttribute('placeholder', `(${Util.formatNumber(this.ogl.calcExpeditionMax().max)})`);
}
//Util.formatInput(input);
}
else if(opt == 'keyboardActions')
{
label.innerHTML = `<button class="material-icons">keyboard_alt</button>`;
label.querySelector('button').addEventListener('click', () =>
{
Util.runAsync(() => this.ogl._ui.openKeyboardActions()).then(e => this.ogl._popup.open(e));
});
}
else if(opt == 'sim' || opt == 'converter')
{
const list = opt == 'sim' ? Util.simList : Util.converterList;
label.innerHTML = ``;
const select = Util.addDom('select', { parent:label, class:'dropdownInitialized', child:'<option value="false" selected disabled>-</option>', onchange:() =>
{
this.ogl.db.options[opt] = select.value;
}});
Object.entries(list).forEach(entry =>
{
const selectOption = Util.addDom('option', { parent:select, child:entry[0], value:entry[0] });
if(this.ogl.db.options[opt] == entry[0]) selectOption.selected = true;
});
}
else if(opt == 'expeditionBigShips')
{
label.innerHTML = `<button class="material-icons">rocket</button>`;
label.querySelector('button').addEventListener('click', () =>
{
Util.runAsync(() => this.ogl._ui.openExpeditionFiller()).then(e => this.ogl._popup.open(e));
});
}
else if(opt == 'displayMiniStats')
{
label.innerHTML = `<div class="ogl_choice" data-limiter="day">D</div><div class="ogl_choice" data-limiter="week">W</div><div class="ogl_choice" data-limiter="month">M</div>`;
label.querySelectorAll('div').forEach(button =>
{
button.addEventListener('click', () =>
{
this.ogl.db.options[opt] = button.getAttribute('data-limiter');
this.ogl._stats.showMiniRecap();
label.querySelector('.ogl_active') && label.querySelector('.ogl_active').classList.remove('ogl_active');
button.classList.add('ogl_active');
});
if(button.getAttribute('data-limiter') == this.ogl.db.options[opt])
{
button.classList.add('ogl_active');
}
});
}
else if(opt == 'spyTableRules')
{
label.innerHTML = `<button class="material-icons">filter_alt</button>`;
label.querySelector('button').addEventListener('click', () =>
{
this.ogl._message.openSpyTableRules();
});
}
else if(opt == 'ptreTeamKey')
{
label.classList.add('tooltipLeft');
label.setAttribute('title', 'Format:<br>TM-XXXX-XXXX-XXXX-XXXX');
const input = Util.addDom('input', { type:'password', placeholder:'TM-XXXX-XXXX-XXXX-XXXX', value:localStorage.getItem('ogl-ptreTK') || '', parent:label,
oninput:() =>
{
if(input.value && (input.value.replace(/-/g, '').length != 18 || input.value.indexOf('TM') != 0))
{
input.classList.add('ogl_danger');
}
else
{
input.classList.remove('ogl_danger');
localStorage.setItem('ogl-ptreTK', input.value);
this.ogl.ptreKey = input.value;
}
},
onfocus:() => input.type = 'text',
onblur:() => input.type = 'password'
});
}
else if(opt == 'ptreLogs')
{
label.innerHTML = `<button class="material-icons">bug_report</button>`;
label.querySelector('button').addEventListener('click', () =>
{
this.ogl.PTRE.displayLogs();
});
}
else if(opt == 'manageData')
{
label.innerHTML = `<button class="material-icons">database</button>`;
label.querySelector('button').addEventListener('click', () =>
{
Util.runAsync(() => this.ogl._ui.openDataManager()).then(e => this.ogl._popup.open(e));
});
}
});
this.ogl._ui.openSide(container, 'settings', buttonSource);
}
openPinned(buttonSource)
{
this.ogl._ui.openSide(Util.addDom('div', { class:'ogl_loading' }), 'pinned', buttonSource);
Util.runAsync(() =>
{
const container = Util.addDom('div', {class:'ogl_pinned', child:'<h2>Pinned players<i class="material-icons">keep</i></h2>'});
const tabs = Util.addDom('div', { class:'ogl_tabs ogl_flagSelector material-icons', parent:container });
const list = Util.addDom('div', { class:'ogl_list', parent:container });
this.ogl.flagsList.forEach(pin =>
{
if(pin != 'none')
{
const tab = Util.addDom('div', { parent:tabs, 'data-flag':pin, onclick:() =>
{
list.innerText = '';
tabs.querySelector('[data-flag].ogl_active')?.classList.remove('ogl_active');
tab.classList.add('ogl_active');
this.ogl.db.lastPinTab = pin;
if(pin == 'ptre' && this.ogl.ptreKey)
{
const actionList = Util.addDom('div', { class:'ogl_grid', parent:list });
Util.addDom('button', { class:'ogl_button', child:this.ogl._lang.find('ptreSyncTarget'), parent:actionList, onclick:() =>
{
this.ogl.PTRE.syncTargetList();
}});
Util.addDom('button', { class:'ogl_button', child:this.ogl._lang.find('ptreManageTarget'), parent:actionList, onclick:() =>
{
window.open(this.ogl.PTRE.manageSyncedListUrl, '_blank');
}})
Util.addDom('hr', { parent:list });
}
Object.values(this.ogl.db.udb).filter(u => u.pin == this.ogl.db.lastPinTab).sort((a, b) => a.score?.globalRanking - b.score?.globalRanking).forEach(player =>
{
if(player.uid)
{
this.addPinnedItemToList(player, list);
}
});
if(!list.querySelector('[data-uid]') && !list.querySelector('.ogl_button')) list.innerHTML = `<p class="ogl_emptyList">${this.ogl._lang.find('emptyPlayerList')}</p>`;
}});
if(pin == this.ogl.db.lastPinTab)
{
tab.click();
}
}
});
const recentTab = Util.addDom('div', { 'data-flag':'recent', parent:tabs, onclick:() =>
{
this.ogl.db.lastPinTab = 'recent';
list.innerText = '';
tabs.querySelector('[data-flag].ogl_active')?.classList.remove('ogl_active');
recentTab.classList.add('ogl_active');
this.ogl.db.lastPinnedList.forEach(id =>
{
const player = this.ogl.db.udb[id];
if(player?.uid)
{
this.addPinnedItemToList(player, list);
}
});
if(!list.querySelector('[data-uid]')) list.innerText = this.ogl._lang.find('emptyPlayerList');
}});
if(this.ogl.db.lastPinTab == 'recent')
{
recentTab.click();
}
return container;
})
.then(container => this.ogl._ui.openSide(container, 'pinned', buttonSource));
}
addPinnedItemToList(player, list)
{
const item = Util.addDom('div', { parent:list });
const playerDiv = Util.addDom('span',
{
class:`tooltipLeft tooltipClose tooltipUpdate ${player.status || 'status_abbr_active'}`,
parent:item,
child:typeof player.name == typeof '' ? player.name : '?',
});
this.ogl._ui.turnIntoPlayerLink(player.uid, playerDiv);
const page = Math.max(1, Math.ceil((player.score?.globalRanking || 100) / 100));
const rankLink = Util.addDom('a', { class:'ogl_ranking', href:`https://${window.location.host}/game/index.php?page=highscore&site=${page}&searchRelId=${player.uid}`, child:'#'+player.score?.globalRanking || '?' });
Util.addDom('div', { parent:item, child:rankLink.outerHTML });
this.ogl._ui.addPinButton(item, player.uid);
Util.addDom('i', { class:'material-icons', parent:item, child:'delete', onclick:() =>
{
this.ogl.db.lastPinnedList.splice(this.ogl.db.lastPinnedList.findIndex(e => e == player.uid), 1);
item.remove();
delete this.ogl.db.udb[player.uid].pin;
}});
}
openPinnedDetail(id, update)
{
id = parseInt(id);
this.ogl._ui.openSide(Util.addDom('div', { class:'ogl_loading' }), id);
const updateSide = () =>
{
const player = this.ogl.db.udb[id];
if(!player) return;
const container = Util.addDom('div', { class:'ogl_pinDetail' });
const status = this.ogl.playerStatus.find(e => e.defaultTag == player.status)?.class || 'status_abbr_active';
Util.addDom('div', { parent:container, class:'material-icons ogl_back', child:'arrow_back', onclick:() => { this.openPinned() } })
const title = Util.addDom('h2', { class:status, parent:container, child:player.name });
const score = Util.addDom('div', { class:'ogl_score', parent:container });
const actions = Util.addDom('div', { class:'ogl_actions', parent:container });
const list = Util.addDom('div', { class:'ogl_list', parent:container });
this.ogl._ui.addPinButton(title, id);
// write
const writeIcon = Util.addDom('div', { child:'edit', class:'material-icons ogl_button', parent:actions, onclick:() =>
{
if(!document.querySelector('#chatBar'))
{
window.location.href = `https://${window.location.host}/game/index.php?page=chat&playerId=${id}`;
}
}});
if(document.querySelector('#chatBar'))
{
writeIcon.classList.add('js_openChat');
writeIcon.setAttribute('data-playerId', id);
}
// buddy
Util.addDom('a', { child:'person_add', class:'material-icons ogl_button overlay', parent:container.querySelector('.ogl_actions'), href:`https://${window.location.host}/game/index.php?page=ingame&component=buddies&action=7&id=${id}&ajax=1`, onclick:() =>
{
tippy.hideAll();
}});
// ignore
Util.addDom('div', { child:'block', class:'material-icons ogl_button', parent:actions, onclick:() =>
{
window.location.href = `https://${window.location.host}/game/index.php?page=ignorelist&action=1&id=${id}`;
}});
// mmorpgstat
Util.addDom('div', { child:'query_stats', class:'material-icons ogl_button', parent:actions, onclick:() =>
{
window.open(Util.genMmorpgstatLink(this.ogl, id), '_blank');
}});
// ptre get player info
Util.addDom('div', { child:'ptre', class:'material-icons ogl_button', parent:actions, onclick:() =>
{
this.ogl.PTRE.getPlayerInfo({ name:player.name, id:id });
}});
Util.addDom('div', { child:'sync', class:'material-icons ogl_button', parent:actions, onclick:() =>
{
this.ogl.PTRE.getPlayerPositions({ name:player.name, id:id });
}});
this.ogl.db.lastPinnedList = Array.from(new Set([id, ...this.ogl.db.lastPinnedList].map(Number)));
if(this.ogl.db.lastPinnedList.length > 30) this.ogl.db.lastPinnedList.length = 30;
if(!update)
{
Util.addDom('div', { class:'ogl_loading', parent:container });
this.ogl._ui.openSide(container, id);
this.ogl.PTRE.getPlayerPositions({ name:player.name, id:id }); // includes _fetch.fetchPlayerAPI()
}
const page = Math.max(1, Math.ceil((player.score?.globalRanking || 100) / 100));
const rankLink = Util.addDom('a', { class:'ogl_ranking', href:`https://${window.location.host}/game/index.php?page=highscore&site=${page}&searchRelId=${player.uid}`, child:'#'+player.score?.globalRanking || '?' });
title.innerHTML = `${player.name} ${rankLink.outerHTML}`;
this.ogl._ui.addPinButton(title, id);
score.innerHTML =
`
<div class="ogl_line tooltip" title="Global"><i class="material-icons">crown</i><div>${Util.formatNumber(player.score?.global)}</div></div>
<div class="ogl_line tooltip" title="Economy"><i class="material-icons">diamond</i><div>${Util.formatNumber(player.score?.economy)}</div></div>
<div class="ogl_line tooltip" title="Research"><i class="material-icons">science</i><div>${Util.formatNumber(player.score?.research)}</div></div>
<div class="ogl_line tooltip" title="Lifeforms"><i class="material-icons">genetics</i><div>${Util.formatNumber(player.score?.lifeform)}</div></div>
<div class="ogl_line tooltip" title="Fleet"><i class="material-icons">rocket_launch</i><div>${Util.formatNumber(Util.getPlayerScoreFD(player.score, 'fleet'))}</div></div>
<div class="ogl_line tooltip" title="Defense"><i class="material-icons">security</i><div>${Util.formatNumber(Util.getPlayerScoreFD(player.score, 'defense'))}</div></div>
<div class="ogl_line tooltip" title="Astro lvl: ${player.astro || '?'}"><i class="material-icons">planet</i><div>${Util.formatNumber(player.astro ? (Math.ceil(player.astro / 2) + 1) + ' planets max.' : '?')}</div></div>
`;
let lastCoords = 0;
let group = 1;
let index = 1;
player.planets.sort((a, b) => Util.coordsToID(a) - Util.coordsToID(b)).forEach((planetID) =>
{
const planet = this.ogl.db.pdb[planetID];
if(!planet) return;
const date = new Date(planet.api);
const dateDiff = Math.floor((serverTime.getTime() - date) / (1000 * 3600 * 24));
const hourDiff = Math.round(((serverTime.getTime() - date % 86400000) % 3600000) / 60000);
const line = Util.addDom('div', { parent:list });
if(planet.home) line.classList.add('ogl_home');
let newCoords = Util.coordsToID(planet.coo).slice(0, -3);
if(lastCoords === newCoords) line.setAttribute('data-group', group);
else if(line.previousElementSibling?.getAttribute('data-group')) group++;
lastCoords = newCoords;
Util.addDom('div', { child:index, parent:line });
Util.addDom('div', { child:planet.coo, parent:line, 'data-galaxy':planet.coo });
const debrisDiv = Util.addDom('div', { class:'tooltip', 'data-debris-coords':planet.coo, title:'Debris<br>'+Util.formatNumber(planet.debris || 0), child:Util.formatToUnits(planet.debris || 0), parent:line });
if(this.ogl._movement?.destinationList?.[planet.coo]?.indexOf('8') >= 0) debrisDiv.classList.add('ogl_attacked');
this.ogl._ui.addSpyIcons(line, planet.coo.split(':'), false, true);
let ageStr = !dateDiff && dateDiff !== 0 ? '?' : dateDiff > 0 ? `${dateDiff}${LocalizationStrings.timeunits.short.hour} ago` : `${hourDiff}${LocalizationStrings.timeunits.short.minute} ago`;
const dateDiv = Util.addDom('date', { class:'tooltipLeft', child:ageStr, title:`<span>${date.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})}</span> <span>${date.toLocaleTimeString('de-DE')}</span>`, parent:line });
if(dateDiff >= 5) dateDiv.classList.add('ogl_danger');
else if(dateDiff >= 3) dateDiv.classList.add('ogl_warning');
index += 1;
//Util.addDom('date', { child:`<span>${date.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})}</span><span>${date.toLocaleTimeString('de-DE')}</span>`, parent:line });
});
this.ogl._ui.openSide(container, id);
setTimeout(() => this.ogl._shortcut.load(), 50);
this.ogl._galaxy.checkCurrentSystem();
}
Util.runAsync(() =>
{
this.ogl._fetch.fetchPlayerAPI(id, false, () => updateSide());
});
}
openTagged(buttonSource)
{
this.ogl._ui.openSide(Util.addDom('div', { class:'ogl_loading' }), 'tagged');
Util.runAsync(() =>
{
const container = Util.addDom('div', {class:'ogl_tagged', child:'<h2>Tagged planets<i class="material-icons">stroke_full</i></h2>'});
const tabs = Util.addDom('div', { class:'ogl_tabs ogl_tagSelector material-icons', parent:container });
const inputs = Util.addDom('div', { class:'ogl_actions', parent:container });
Util.addDom('hr', { parent:container });
const list = Util.addDom('div', { class:'ogl_list', parent:container, child:'<p class="ogl_emptyList">Select a galaxy/system range</p>' });
const buildList = () =>
{
const start = Util.coordsToID(`${gStart.value}:${sStart.value}:000`);
const end = Util.coordsToID(`${gEnd.value}:${sEnd.value}:000`);
const items = this.getTaggedItems(start, end);
list.innerText = '';
if(items.length < 1)
{
Util.addDom('p', { child:'No result', parent:list } );
}
else
{
let nextTargetFound = false;
let newList = [];
items.forEach((item, index) =>
{
const coords = item.match(/.{1,3}/g).map(Number).join(':');
const coordsID = Util.coordsToID(coords);
const line = Util.addDom('div', { parent:list });
Util.addDom('div', { child:index+1, parent:line });
Util.addDom('div', { child:coords, 'data-galaxy':coords, parent:line});
const target = Util.addDom('div', { class:'material-icons tooltip ogl_nextQuickTarget', title:'Select as next quick raid target', child:'swords', parent:line, onclick:() =>
{
const start = Util.coordsToID(coords);
const end = Util.coordsToID(`${gEnd.value}:${sEnd.value}:000`);
this.getTaggedItems(start, end, true);
this.ogl.db.quickRaidList = this.tmpRaidList;
this.ogl._notification.addToQueue(`You can now use [${this.ogl.db.options.keyboardActions.quickRaid}] on fleet page to attack next target`, true);
setTimeout(() => this.ogl._shortcut.load(), 50);
list.querySelectorAll('.ogl_nextQuickTarget.ogl_active').forEach(e => e.classList.remove('ogl_active'));
target.classList.add('ogl_active');
}});
if(this.ogl.db.quickRaidList && this.ogl.db.quickRaidList?.[0] == coordsID)
{
target.classList.add('ogl_active');
nextTargetFound = true;
}
if(nextTargetFound) newList.push(coordsID);
this.ogl._ui.addSpyIcons(line, coords);
this.ogl._ui.addTagButton(line, coords);
});
this.ogl.db.quickRaidList = nextTargetFound ? newList : [];
}
}
Object.keys(this.ogl.db.tags).forEach(tag =>
{
if(tag != 'none')
{
const tab = Util.addDom('div', { parent:tabs, 'data-tag':tag, onclick:() =>
{
if(this.ogl.db.tags[tag])
{
this.ogl.db.tags[tag] = false;
tab.classList.add('ogl_off');
}
else
{
this.ogl.db.tags[tag] = true;
tab.classList.remove('ogl_off');
}
}});
if(!this.ogl.db.tags[tag]) tab.classList.add('ogl_off');
}
});
const currentCoords = this.ogl.currentPlanet.obj.coords.split(':');
const gStart = Util.addDom('input', { type:'text', min:'1', max:'10', parent:inputs, value:this.ogl.db.lastTaggedInput[0] || currentCoords[0], onblur:e => e.target.value = e.target.value || 1, oninput:() => saveInput() });
const sStart = Util.addDom('input', { type:'text', min:'1', max:'499', parent:inputs, value:this.ogl.db.lastTaggedInput[1] || currentCoords[1], onblur:e => e.target.value = e.target.value || 1, oninput:() => saveInput() });
Util.addDom('div', { class:'material-icons', child:'arrow_right_alt', parent:inputs });
const gEnd = Util.addDom('input', { type:'text', min:'1', max:'10', parent:inputs, value:this.ogl.db.lastTaggedInput[2] || 1, onblur:e => e.target.value = e.target.value || 1, oninput:() => saveInput() });
const sEnd = Util.addDom('input', { type:'text', min:'1', max:'499', parent:inputs, value:this.ogl.db.lastTaggedInput[3] || 1, onblur:e => e.target.value = e.target.value || 1, oninput:() => saveInput() });
const ignoreNoobButton = Util.addDom('label', { class:'status_abbr_noob', parent:inputs, child:this.ogl._lang.find('noob')+'<input class="ogl_hidden" type="checkbox">', onclick:() =>
{
setTimeout(() =>
{
this.ogl.db.lastTaggedInput[4] = ignoreNoobButton.querySelector('input').checked;
this.ogl.db.lastTaggedInput[4] ? ignoreNoobButton.classList.remove('ogl_off') : ignoreNoobButton.classList.add('ogl_off');
buildList();
}, 50);
}});
const ignoreVacationButton = Util.addDom('label', { class:'status_abbr_vacation', parent:inputs, child:this.ogl._lang.find('vacation')+'<input class="ogl_hidden" type="checkbox">', onclick:() =>
{
setTimeout(() =>
{
this.ogl.db.lastTaggedInput[5] = ignoreVacationButton.querySelector('input').checked;
this.ogl.db.lastTaggedInput[5] ? ignoreVacationButton.classList.remove('ogl_off') : ignoreVacationButton.classList.add('ogl_off');
buildList();
}, 50);
}});
Util.addDom('div', { class:'material-icons ogl_button', parent:inputs, child:'search', onclick:() => buildList() });
if(this.ogl.db.lastTaggedInput[0] && this.ogl.db.lastTaggedInput[1] && this.ogl.db.lastTaggedInput[2] && this.ogl.db.lastTaggedInput[3]) buildList();
if(!this.ogl.db.lastTaggedInput[4]) ignoreNoobButton.classList.add('ogl_off');
else ignoreNoobButton.querySelector('input').checked = true;
if(!this.ogl.db.lastTaggedInput[5]) ignoreVacationButton.classList.add('ogl_off');
else ignoreVacationButton.querySelector('input').checked = true;
const saveInput = () =>
{
if(this.timeout) clearTimeout(this.timeout);
this.ogl.db.lastTaggedInput[0] = gStart.value;
this.ogl.db.lastTaggedInput[1] = sStart.value;
this.ogl.db.lastTaggedInput[2] = gEnd.value;
this.ogl.db.lastTaggedInput[3] = sEnd.value;
}
return container;
}).then(container =>
{
this.ogl._ui.openSide(container, 'tagged', buttonSource);
setTimeout(() => this.ogl._shortcut.load(), 50);
});
}
getTaggedItems(rawStart, rawEnd, newFlag)
{
rawStart = parseInt(rawStart);
rawEnd = parseInt(rawEnd);
const displayNoob = this.ogl.db.lastTaggedInput[4];
const displayVacation = this.ogl.db.lastTaggedInput[5];
if(!newFlag)
{
if(rawStart <= rawEnd) rawEnd += 15;
else rawStart += 15;
}
this.tmpRaidList = Object.keys(this.ogl.db.tdb).sort((a, b) => rawStart <= rawEnd ? a-b : b-a).filter(position =>
{
const coords = position.match(/.{1,3}/g).map(Number).join(':');
const status = this.ogl.db.udb[this.ogl.db.pdb[coords]?.uid]?.status;
return this.ogl.db.tags[this.ogl.db.tdb[position].tag]
&& (rawStart <= rawEnd ? position >= rawStart && position <= rawEnd : position <= rawStart && position >= rawEnd)
&& (displayNoob || !status || (!displayNoob && status?.indexOf('n') < 0))
&& (displayVacation || !status || (!displayVacation && (status?.indexOf('v') < 0 && status?.indexOf('b') < 0)))
});
return this.tmpRaidList;
}
checkUpgrade()
{
this.PlanetBuildingtooltip = this.PlanetBuildingtooltip || {};
document.querySelectorAll('.planetlink, .moonlink').forEach(planet =>
{
//if(planet.querySelector('.ogl_buildIconList')) planet.querySelector('.ogl_buildIconList').innerText = '';
if(planet.querySelector('.ogl_buildIconList')) planet.querySelector('.ogl_buildIconList').remove();
const urlParams = new URLSearchParams(planet.getAttribute('href'));
const id = urlParams.get('cp').split('#')[0];
const isMoon = planet.classList.contains('moonlink');
this.PlanetBuildingtooltip[id] = Util.addDom('ul', { class:'ogl_buildList' });
let hasBaseBuilding = false;
let hasBaseResearch = false;
let hasBaseShip = false;
let hasLFBuilding = false;
let hasLFResearch = false;
this.ogl.db.myPlanets[id] = this.ogl.db.myPlanets[id] || {};
Object.values(this.ogl.db.myPlanets[id].upgrades || {}).forEach(upgradeType =>
{
let ready = false;
if(upgradeType?.id) return; // clear old beta data
upgradeType.forEach(upgrade =>
{
if(serverTime.getTime() < upgrade.end)
{
if(!ready)
{
ready = true;
let content = `<i class="material-icons">fiber_manual_record</i><span class="ogl_slidingText" data-text="${upgrade.name}"></span>`;
if(upgrade.lvl) content += `<i class="material-icons">east</i><b>${upgrade.lvl}</b>`;
Util.addDom('li', { parent:this.PlanetBuildingtooltip[id], child:content });
if(upgrade.type == 'baseBuilding') hasBaseBuilding = true;
else if(upgrade.type == 'baseResearch') hasBaseResearch = true;
else if(upgrade.type == 'ship' || upgrade.type == 'def' || upgrade.type == 'mechaShip') hasBaseShip = true;
else if(upgrade.type == 'lfBuilding') hasLFBuilding = true;
else if(upgrade.type == 'lfResearch') hasLFResearch = true;
}
}
});
});
const parent = Util.addDom('div', { class:'ogl_buildIconList', parent:planet });
if(hasBaseBuilding) Util.addDom('div', { class:'ogl_buildIcon', 'data-type':'building', parent:parent });
if(hasBaseResearch) Util.addDom('div', { class:'ogl_buildIcon', 'data-type':'research', parent:parent });
if(hasBaseShip) Util.addDom('div', { class:'ogl_buildIcon', 'data-type':'ship', parent:parent });
if(hasLFBuilding) Util.addDom('div', { class:'ogl_buildIcon', 'data-type':'lfbuilding', parent:parent });
if(hasLFResearch) Util.addDom('div', { class:'ogl_buildIcon', 'data-type':'lfresearch', parent:parent });
});
}
}
class FleetManager extends Manager
{
load()
{
this.validationReady = true;
this.miniFleetQueue = [];
this.updateSpyFunctions();
if(this.ogl.page == 'fleetdispatch')
{
this.totalCapacity = 0;
this.capacityWrapper = Util.addDom('div', { 'class':'capacityProgress', parent:document.querySelector('#fleet1 .content'), onclick:() => document.querySelector(`.ogl_requiredShips .ogl_${this.ogl.db.options.defaultShip}`).click() });
this.capacityBar = Util.addDom('progress', { 'data-capacity':'', max:100, value:0, parent:this.capacityWrapper });
this.resOnPlanet = { metal:'metalOnPlanet', crystal:'crystalOnPlanet', deut:'deuteriumOnPlanet', food:'foodOnPlanet' };
this.cargo = { metal:'cargoMetal', crystal:'cargoCrystal', deut:'cargoDeuterium', food:'cargoFood' };
this.initialTarget = JSON.parse(JSON.stringify(targetPlanet));
// wait for fleetDispatcher to be ready
let initInterval = setInterval(() =>
{
if(unsafeWindow.fleetDispatcher)
{
// initialize realTarget
this.setRealTarget(this.initialTarget);
fleetDispatcher.targetPlanet = fleetDispatcher.realTarget;
// get initial resources / ships on planet
this.initialResOnPlanet = { metal:fleetDispatcher.metalOnPlanet, crystal:fleetDispatcher.crystalOnPlanet, deut:fleetDispatcher.deuteriumOnPlanet, food:fleetDispatcher.foodOnPlanet };
this.initialShipsOnPlanet = JSON.parse(JSON.stringify(fleetDispatcher.shipsOnPlanet));
/// overwrite default methods
if(!this.overwrited) this.overwrite();
if(!this.hasBeenRefreshed) this.switchSelfTargetType();
if(!fleetDispatcher.fetchTargetPlayerDataTimeout)
{
// force shipsData fetch (can happen when the server is laggy)
if(!unsafeWindow.shipsData || !fleetDispatcher?.fleetHelper?.shipsData)
{
let params = {};
fleetDispatcher.appendShipParams(params);
fleetDispatcher.appendTargetParams(params);
fleetDispatcher.appendTokenParams(params);
params.union = fleetDispatcher.union;
$.post(fleetDispatcher.checkTargetUrl, params, response =>
{
let data = JSON.parse(response);
fleetDispatcher.fleetHelper.shipsData = data.shipsData;
fleetDispatcher.updateToken(data.newAjaxToken);
this.init();
clearInterval(initInterval);
});
}
else
{
this.init();
clearInterval(initInterval);
}
}
}
}, 50);
}
}
overwrite()
{
this.overwrited = true;
fleetDispatcher.fleetHelper.getShipData = shipID =>
{
return fleetDispatcher?.fleetHelper?.shipsData?.[shipID] || shipsData[shipID];
}
fleetDispatcher.refreshDataAfterAjax = data =>
{
this.hasBeenRefreshed = true;
const ownPlanet = Object.values(ogl.db.myPlanets).find(e => e.coords == `${data.targetPlanet.galaxy}:${data.targetPlanet.system}:${data.targetPlanet.position}`);
fleetDispatcher.setOrders(data.orders);
fleetDispatcher.mission = 0;
fleetDispatcher.setTargetInhabited(data.targetInhabited);
fleetDispatcher.setTargetPlayerId(data.targetPlayerId);
fleetDispatcher.setTargetPlayerName(data.targetPlayerName);
fleetDispatcher.setTargetIsStrong(data.targetIsStrong);
fleetDispatcher.setTargetIsOutlaw(data.targetIsOutlaw);
fleetDispatcher.setTargetIsBuddyOrAllyMember(data.targetIsBuddyOrAllyMember);
fleetDispatcher.setTargetPlayerColorClass(data.targetPlayerColorClass);
fleetDispatcher.setTargetPlayerRankIcon(data.targetPlayerRankIcon);
fleetDispatcher.setPlayerIsOutlaw(data.playerIsOutlaw);
fleetDispatcher.targetPlanet.galaxy = data.targetPlanet.galaxy;
fleetDispatcher.targetPlanet.system = data.targetPlanet.system;
fleetDispatcher.targetPlanet.position = data.targetPlanet.position;
fleetDispatcher.targetPlanet.type = data.targetPlanet.type;
fleetDispatcher.targetPlanet.name = data.targetPlanet.name;
this.setRealTarget(JSON.parse(JSON.stringify(fleetDispatcher.targetPlanet)));
/*if(JSON.stringify(fleetDispatcher.realTarget) == JSON.stringify(fleetDispatcher.currentPlanet))
{
this.setRealTarget(fleetDispatcher.realTarget, { type:fleetDispatcher.realTarget.type == 1 ? 3 : 1 });
}*/
if(!data.targetOk && this.isQuickRaid)
{
this.ogl.db.quickRaidList.shift();
}
setTimeout(() =>
{
const hasMission = (fleetDispatcher.getAvailableMissions() || []).indexOf(fleetDispatcher.mission) > -1;
if(!hasMission && this.lastMissionOrder && (fleetDispatcher.getAvailableMissions() || []).indexOf(this.lastMissionOrder) > -1)
{
fleetDispatcher.mission = this.lastMissionOrder;
}
else if(!ownPlanet)
{
if(data.targetPlanet.type == 2) fleetDispatcher.mission = 8;
else if(fleetDispatcher.union) fleetDispatcher.mission = 2;
else fleetDispatcher.mission = 1;
}
else if(!hasMission && fleetDispatcher.currentPage == 'fleet2' && (fleetDispatcher.getAvailableMissions() || []).length == 1)
{
fleetDispatcher.mission = fleetDispatcher.getAvailableMissions()[0];
}
else if(!hasMission && (fleetDispatcher.getAvailableMissions() || []).indexOf(this.ogl.db.options.defaultMission) > -1)
{
fleetDispatcher.mission = this.ogl.db.options.defaultMission;
}
else if(hasMission)
{
fleetDispatcher.mission = this.lastMissionOrder;
}
else if(this.ogl.mode && this.ogl.db.options.defaultMission == 1)
{
fleetDispatcher.mission = 3;
}
fleetDispatcher.refresh();
}, 50);
this.switchSelfTargetType();
}
fleetDispatcher.selectShip = (shipID, number) =>
{
let shipsAvailable = fleetDispatcher.getNumberOfShipsOnPlanet(shipID);
const tech = this.ogl._dom.tech[shipID];
const input = tech._ogl.input;
if(shipsAvailable === 0 || (number > shipsAvailable && !tech?.classList.contains('ogl_notEnough'))) input?.classList.add('ogl_flashNotEnough');
else input.classList.remove('ogl_flashNotEnough');
number = Math.min(shipsAvailable, number);
if (number <= 0) fleetDispatcher.removeShip(shipID);
else if (fleetDispatcher.hasShip(shipID)) fleetDispatcher.updateShip(shipID, number);
else fleetDispatcher.addShip(shipID, number);
Util.formatInput(input, false, true);
fleetDispatcher.refresh();
}
fleetDispatcher.trySubmitFleet1 = () =>
{
if(fleetDispatcher.currentPage != 'fleet1') return;
fleetDispatcher.targetPlanet = fleetDispatcher.realTarget;
if(fleetDispatcher.validateFleet1() === false)
{
this.validationReady = true;
return;
}
fleetDispatcher.switchToPage('fleet2');
}
Util.overWrite('refresh', fleetDispatcher, false, () =>
{
/*if(fleetDispatcher.shipsToSend.length > 0) document.body.classList.add('ogl_destinationPicker');
else if(!document.body.classList.contains('ogl_initHarvest')) document.body.classList.remove('ogl_destinationPicker');*/
// capacity bar
let totalResources = fleetDispatcher.metalOnPlanet + fleetDispatcher.crystalOnPlanet + fleetDispatcher.deuteriumOnPlanet + fleetDispatcher.foodOnPlanet;
this.totalCapacity = this.totalCapacity || 1;
const percentCapacity = Math.floor((fleetDispatcher.getCargoCapacity() / this.totalCapacity) * 100) || 0;
const percentResources = Math.floor((fleetDispatcher.getCargoCapacity() / totalResources) * 100) || 0;
const percentRequired = Math.floor((totalResources / this.totalCapacity) * 100) || 0;
this.capacityBar.style.setProperty('--capacity', `linear-gradient(to right, #641717, #938108 ${percentRequired * .8}%, #055c54 ${percentRequired}%)`);
this.capacityWrapper.style.setProperty('--currentCapacityPercent', Math.min(94, percentCapacity)+'%');
this.capacityWrapper.setAttribute('data-percentResources', Math.min(100, percentResources));
this.capacityWrapper.setAttribute('data-rawCargo', `${Util.formatNumber(fleetDispatcher.getCargoCapacity())} / ${Util.formatNumber(this.totalCapacity)} - (req. ${Util.formatNumber(totalResources)})`);
this.capacityBar.setAttribute('max', 100);
this.capacityBar.setAttribute('value', percentCapacity);
const apiButton = document.querySelector('.show_fleet_apikey');
if(apiButton)
{
apiButton.classList.add('tooltipClose');
apiButton.classList.add('tooltipClick');
/*const apiRaw = Util.addDom('div', {child:apiButton.getAttribute('data-tooltip-title') || apiButton.getAttribute('title') || apiButton.getAttribute('data-title')});
if(apiRaw)
{
const api = apiRaw.querySelector('#FLEETAPI_JSON').getAttribute('value');
apiButton.setAttribute('data-api-code', api);
}*/
}
if(this.ogl._time.timeLoop) this.ogl._time.timeLoop(true);
});
Util.overWrite('updateTarget', fleetDispatcher, () =>
{
document.querySelector('#planetList').classList.add('ogl_notReady');
});
// fix undefined "hasEnoughFuel" value
fleetDispatcher.hasEnoughFuel = () => (this.initialResOnPlanet?.deut || fleetDispatcher.deuteriumOnPlanet) >= fleetDispatcher.getConsumption();
Util.overWrite('selectMission', fleetDispatcher, false, () =>
{
this.lastMissionOrder = fleetDispatcher.mission;
document.querySelector('#fleet2').setAttribute('data-selected-mission', fleetDispatcher.mission);
});
Util.overWrite('switchToPage', fleetDispatcher, () =>
{
if(fleetDispatcher.getFreeCargoSpace() < 0 && fleetDispatcher.cargoFood) { fleetDispatcher.selectMinFood(); fleetDispatcher.selectMaxFood(); }
if(fleetDispatcher.getFreeCargoSpace() < 0 && fleetDispatcher.cargoMetal) { fleetDispatcher.selectMinMetal(); fleetDispatcher.selectMaxMetal(); }
if(fleetDispatcher.getFreeCargoSpace() < 0 && fleetDispatcher.cargoCrystal) { fleetDispatcher.selectMinCrystal(); fleetDispatcher.selectMaxCrystal(); }
if(fleetDispatcher.getFreeCargoSpace() < 0 && fleetDispatcher.cargoDeuterium) { fleetDispatcher.selectMinDeuterium(); fleetDispatcher.selectMaxDeuterium(); }
}, () =>
{
if(fleetDispatcher.currentPage == 'fleet2')
{
document.body.classList.add('ogl_destinationPicker');
fleetDispatcher.focusSendFleet();
}
else if(fleetDispatcher.currentPage == 'fleet1')
{
document.body.classList.remove('ogl_destinationPicker');
fleetDispatcher.focusSubmitFleet1();
}
});
Util.overWrite('stopLoading', fleetDispatcher, () =>
{
if(fleetDispatcher.currentPage == 'fleet2') this.validationReady = true;
});
fleetDispatcher.submitFleet2 = force =>
{
let self = this;
if(self.sent || self.ajaxSuccess) return true;
self.sent = true;
if(fleetDispatcher.realTarget)
{
fleetDispatcher.targetPlanet.galaxy = fleetDispatcher.realTarget.galaxy;
fleetDispatcher.targetPlanet.system = fleetDispatcher.realTarget.system;
fleetDispatcher.targetPlanet.position = fleetDispatcher.realTarget.position;
fleetDispatcher.targetPlanet.type = fleetDispatcher.realTarget.type;
fleetDispatcher.targetPlanet.name = fleetDispatcher.realTarget.name;
fleetDispatcher.refresh();
}
if(fleetDispatcher.realSpeedPercent)
{
fleetDispatcher.speedPercent = fleetDispatcher.realSpeedPercent;
}
force = force || false;
let that = fleetDispatcher;
let params = {};
fleetDispatcher.appendTokenParams(params);
fleetDispatcher.appendShipParams(params);
fleetDispatcher.appendTargetParams(params);
fleetDispatcher.appendCargoParams(params);
fleetDispatcher.appendPrioParams(params);
params.mission = fleetDispatcher.mission;
params.speed = fleetDispatcher.speedPercent;
params.retreatAfterDefenderRetreat = fleetDispatcher.retreatAfterDefenderRetreat === true ? 1 : 0;
params.lootFoodOnAttack = fleetDispatcher.lootFoodOnAttack === true ? 1 : 0;
params.union = fleetDispatcher.union;
if(force) params.force = force;
params.holdingtime = fleetDispatcher.getHoldingTime();
fleetDispatcher.startLoading();
$.post(fleetDispatcher.sendFleetUrl, params, function(response)
{
let data = JSON.parse(response);
if(data.success === true)
{
fadeBox(data.message, false);
$("#sendFleet").removeAttr("disabled");
self.fleetSent(data.redirectUrl);
}
else
{
setTimeout(() => self.sent = false, 500);
if(data.responseArray && data.responseArray.limitReached && !data.responseArray.force)
{
that.updateToken(data.newAjaxToken || '');
errorBoxDecision(that.loca.LOCA_ALL_NETWORK_ATTENTION, that.locadyn.localBashWarning, that.loca.LOCA_ALL_YES, that.loca.LOCA_ALL_NO, function () { that.submitFleet2(true); });
}
else
{
that.displayErrors(data.errors);
that.updateToken(data.newAjaxToken || '');
$("#sendFleet").removeAttr("disabled");
that.stopLoading();
}
}
});
};
Util.overWrite('refreshTargetPlanet', fleetDispatcher, () =>
{
// update ACS data
if(fleetDispatcher.union)
{
// preselect default mission
fleetDispatcher.mission = 2;
fleetDispatcher.refresh();
const acsEndTime = (Object.values(fleetDispatcher.unions).find(a => a.id == fleetDispatcher.union)?.time || 0) * 1000;
if(acsEndTime)
{
if(document.querySelector('.ogl_acsInfo')) return;
const timeObj = this.ogl._time.getObj(acsEndTime);
const acsEnd = this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server;
Util.addDom('hr', { prepend:document.querySelector('#fleetBriefingPart1') });
const liLeft = Util.addDom('li', { class:'ogl_acsInfo', child:"Time remaining: ", prepend:document.querySelector('#fleetBriefingPart1') });
const liOffset = Util.addDom('li', { class:'ogl_acsInfo', child:'Time difference: ', prepend:document.querySelector('#fleetBriefingPart1') });
const spanLeft = Util.addDom('span', { class:'ogl_warning value', parent:liLeft });
const spanOffset = Util.addDom('span', { class:'value', parent:liOffset });
clearInterval(this.acsInterval);
this.acsInterval = setInterval(() =>
{
if(!fleetDispatcher.getDuration()) return;
const currentTime = this.ogl.db.options.useClientTime ? localTime.getTime() : serverTime.getTime();
const fleetDurationLeft = fleetDispatcher.getDuration() * 1000;
const acsDurationLeft = acsEnd - currentTime;
const acsDurationLeftWithMaxOffset = acsDurationLeft * 1.3;
const timeLeft = acsDurationLeftWithMaxOffset - fleetDurationLeft;
const timeEnd = timeLeft > 0 ? this.ogl._time.durationToHMS(timeLeft) : 'Too late';
const delta = fleetDurationLeft - acsDurationLeft;
spanOffset.className = 'value';
spanLeft.className = 'value';
spanLeft.textContent = timeEnd;
if(fleetDurationLeft > acsDurationLeftWithMaxOffset)
{
spanOffset.textContent = `Too late`;
spanOffset.classList.add('ogl_danger');
spanLeft.classList.add('ogl_danger');
}
else if(fleetDurationLeft > acsDurationLeft)
{
spanOffset.textContent = `+${new Date(delta).toISOString().slice(11,19)}`;
spanOffset.classList.add('ogl_warning');
spanLeft.classList.add('ogl_warning');
}
else
{
spanOffset.textContent = '+00:00:00';
spanOffset.classList.add('ogl_ok');
spanLeft.classList.add('ogl_ok');
}
}, 333);
}
}
if(!fleetDispatcher.mission)
{
let urlParams = new URLSearchParams(window.location.search);
if(urlParams.get('mission')) fleetDispatcher.mission = urlParams.get('mission');
else fleetDispatcher.mission = this.ogl.db.options.defaultMission;
fleetDispatcher.refresh();
}
});
}
switchSelfTargetType()
{
if(JSON.stringify(fleetDispatcher.realTarget) == JSON.stringify(fleetDispatcher.currentPlanet))
{
if(this.ogl.db.options.defaultMission != 1 || (fleetDispatcher.cargoMetal + fleetDispatcher.cargoCrystal + fleetDispatcher.cargoDeuterium > 0) || this.ogl.mode === 2 || this.ogl.mode === 3)
{
this.setRealTarget(fleetDispatcher.realTarget, { type:fleetDispatcher.realTarget.type == 1 ? 3 : 1 });
}
}
}
init()
{
this.isReady = true;
//document.querySelector('.planetlink.active, .moonlink.active')?.classList.add('ogl_disabled');
// preselect related planet/moon
/*if(JSON.stringify(fleetDispatcher.realTarget) == JSON.stringify(fleetDispatcher.currentPlanet))
{
this.setRealTarget(fleetDispatcher.realTarget, { type:fleetDispatcher.realTarget.type == 1 ? 3 : 1 });
}*/
this.addLimiters();
if(this.ogl.mode === 3 && this.ogl.cache.toSend)
{
this.prefillTodolistCargo();
}
else
{
this.ogl.db.harvestCoords = undefined;
}
if(this.ogl._dom.warning) return;
this.updateSpeedBar();
// save ships data in OGL DB
this.ogl.shipsList.forEach(shipID =>
{
if(fleetDispatcher.fleetHelper.shipsData?.[shipID])
{
const data = fleetDispatcher.fleetHelper.shipsData[shipID];
const tech = this.ogl._dom.tech[shipID];
this.ogl.db.shipsCapacity[shipID] = data.cargoCapacity || data.baseCargoCapacity;
if(!tech) return;
const content = `
<div class="ogl_shipDataInfo">
<div class="ogl_icon ogl_${shipID}">${data.name}</div><hr>
<i class="material-icons">send</i> Amount : <b>${Util.formatNumber(parseInt(tech._ogl.amount.getAttribute('data-value')))}</b><br>
<i class="material-icons">package_2</i> Capacity : <b>${Util.formatNumber(data.cargoCapacity || data.baseCargoCapacity)}</b><br>
<i class="material-icons">mode_heat</i> Consumption : <b>${Util.formatNumber(data.fuelConsumption)}</b><br>
<i class="material-icons">speed</i> Speed : <b>${Util.formatNumber(data.speed)}</b>
</div>
`;
tech.setAttribute('title', content);
}
});
fleetDispatcher.selectMission((this.ogl.mode === 3 && this.ogl.db.options.defaultMission === 8 ? 3 : parseInt(fleetDispatcher.mission || this.ogl.db.options.defaultMission)));
fleetDispatcher.speedPercent = fleetDispatcher.speedPercent || 10;
fleetDispatcher.realSpeedPercent = fleetDispatcher.speedPercent;
if(this.ogl.mode === 1 || this.ogl.mode === 2)
{
fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, this.shipsForResources());
fleetDispatcher.selectMaxAll();
}
else if(this.ogl.mode === 5 && fleetDispatcher.expeditionCount < fleetDispatcher.maxExpeditionCount)
{
this.selectExpedition(this.ogl.db.lastExpeditionShip || this.ogl.db.options.defaultShip);
}
if(fleetDispatcher.mission == 8)
{
fleetDispatcher.targetPlanet.type = 2;
}
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
if(this.ogl._dom.secondCol)
{
requestAnimationFrame(() =>
{
this.ogl._dom.sendAll.classList.add('material-icons');
this.ogl._dom.sendAll.innerText = 'keyboard_double_arrow_right';
this.ogl._dom.resetAll.classList.add('material-icons');
this.ogl._dom.resetAll.innerText = 'exposure_zero';
});
const sender = Util.addDom('div', { title:'loading...', child:'cube-send', class:'material-icons tooltipRight tooltipClose tooltipClick tooltipUpdate', parent:this.ogl._dom.secondCol, ontooltip:() =>
{
const container = Util.addDom('div', { class:'ogl_resourcesPreselection' });
const resources = ['metal', 'crystal', 'deut', 'food'];
resources.forEach(resourceName =>
{
const item = Util.addDom('div', { class:`ogl_icon ogl_${resourceName}`, parent:container, onclick:() =>
{
input.value = input.value == fleetDispatcher[this.resOnPlanet[resourceName]] ? 0 : fleetDispatcher[this.resOnPlanet[resourceName]];
fleetDispatcher[this.cargo[resourceName]] = input.value;
input.dispatchEvent(new Event('input'));
}});
const input = Util.addDom('input', { type:'text', parent:item,
onclick:e =>
{
e.stopPropagation();
},
oninput:() =>
{
Util.formatInput(input, () =>
{
input.value = Math.min(fleetDispatcher[this.resOnPlanet[resourceName]], (parseInt(input.value.replace(/\D/g, '')) || 0));
fleetDispatcher[this.cargo[resourceName]] = input.value;
input.value = (parseInt(input.value.replace(/\D/g, '') || 0)).toLocaleString('fr-FR');
});
}});
});
Util.addDom('hr', { parent:container });
Util.addDom('div', { class:'ogl_button ogl_formValidation', child:'OK', parent:container, onclick:() =>
{
let total = 0;
container.querySelectorAll('input').forEach(input =>
{
total += parseInt(input.value.replace(/\D/g, '')) || 0;
});
if(total > 0) fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, this.shipsForResources(false, total));
container.querySelectorAll('input').forEach((input, index) => fleetDispatcher[this.cargo[resources[index]]] = parseInt(input.value.replace(/\D/g, '') || 0));
fleetDispatcher.refresh();
setTimeout(() => fleetDispatcher.focusSubmitFleet1(), 50);
tippy.hideAll();
}});
//this.ogl._popup.open(container);
if(sender._tippy)
{
sender._tippy.setContent(container);
}
else
{
this.ogl._tooltip.update(container);
}
setTimeout(() => container.querySelector('input').focus(), 100);
}});
Util.addDom('div', { title:this.ogl._lang.find('fleetQuickCollect'), child:'local_shipping', class:'material-icons tooltip ogl_quickCollectBtn', parent:this.ogl._dom.secondCol, onclick:() =>
{
this.ogl._dom.requiredShips.querySelector(`.ogl_${this.ogl.db.options.defaultShip}`)?.click();
}});
// todo
/*Util.addDom('div', { title:this.ogl._lang.find('fleetQuickCollect'), child:'REC <span class="material-icons">fiber_manual_record</span>', class:'tooltip ogl_recordBtn', parent:this.ogl._dom.secondCol, onclick:() =>
{
}});*/
}
}
setRealTarget(obj, forceParam)
{
// set realTarget and inputs
obj.galaxy = forceParam?.galaxy || obj.galaxy;
obj.system = forceParam?.system || obj.system;
obj.position = forceParam?.position || obj.position;
obj.type = forceParam?.type || obj.type;
obj.name = forceParam?.name || obj.name;
fleetDispatcher.realTarget = obj;
document.querySelector('#galaxy').value = fleetDispatcher.realTarget.galaxy;
document.querySelector('#system').value = fleetDispatcher.realTarget.system;
document.querySelector('#position').value = fleetDispatcher.realTarget.position;
fleetDispatcher.targetPlanet.galaxy = fleetDispatcher.realTarget.galaxy;
fleetDispatcher.targetPlanet.system = fleetDispatcher.realTarget.system;
fleetDispatcher.targetPlanet.position = fleetDispatcher.realTarget.position;
fleetDispatcher.targetPlanet.type = fleetDispatcher.realTarget.type;
// update the flag icon
document.querySelectorAll('.smallplanet').forEach(planet =>
{
const coords = planet.querySelector('.planet-koords').innerText.split(':');
planet.querySelector('.ogl_currentDestination')?.classList.remove('ogl_currentDestination');
if(fleetDispatcher.realTarget.galaxy == coords[0] && fleetDispatcher.realTarget.system == coords[1] && fleetDispatcher.realTarget.position == coords[2])
{
const parent = fleetDispatcher.realTarget.type == 1 ? planet.querySelector('.planetlink') : fleetDispatcher.realTarget.type == 3 ? planet.querySelector('.moonlink') : false;
if(parent) parent.classList.add('ogl_currentDestination');
}
});
}
fleetSent(defaultRedirection)
{
if(this.ajaxSuccess) return;
this.ajaxSuccess = true;
// save fleet data
this.ogl.db.previousFleet = {};
this.ogl.db.previousFleet.shipsToSend = fleetDispatcher.shipsToSend;
this.ogl.db.previousFleet.speedPercent = fleetDispatcher.speedPercent;
this.ogl.db.previousFleet.targetPlanet = JSON.parse(JSON.stringify(fleetDispatcher.targetPlanet)); // unproxify
this.ogl.db.previousFleet.mission = fleetDispatcher.mission;
this.ogl.db.previousFleet.expeditionTime = fleetDispatcher.expeditionTime;
this.ogl.db.previousFleet.cargoMetal = fleetDispatcher.cargoMetal;
this.ogl.db.previousFleet.cargoCrystal = fleetDispatcher.cargoCrystal;
this.ogl.db.previousFleet.cargoDeuterium = fleetDispatcher.cargoDeuterium;
this.ogl.db.previousFleet.cargoFood = fleetDispatcher.cargoFood;
const conso = parseInt(parseFloat(fleetDispatcher.getConsumption() || 0)); // fleetDispatcher.getConsumption() can return a decimal value
// update planet resources left
this.ogl.currentPlanet.obj.metal -= Math.min(this.initialResOnPlanet.metal, fleetDispatcher.cargoMetal);
this.ogl.currentPlanet.obj.crystal -= Math.min(this.initialResOnPlanet.crystal, fleetDispatcher.cargoCrystal);
this.ogl.currentPlanet.obj.deut -= Math.min(this.initialResOnPlanet.deut, fleetDispatcher.cargoDeuterium + conso);
this.ogl.currentPlanet.obj.food -= Math.min(this.initialResOnPlanet.food, fleetDispatcher.cargoFood);
// add conso to stats
const stats = this.ogl._stats.getDayStats(this.ogl._time.timeToKey(serverTime.getTime()));
stats.conso = (stats.conso || 0) + Math.min(this.initialResOnPlanet.deut, conso);
if(this.isQuickRaid) this.ogl.db.quickRaidList.shift();
if(this.ogl.mode === 5 && fleetDispatcher.mission !== 15 && this.ogl.db.options.expeditionRedirect) this.ogl.mode = 0;
if(this.ogl.mode === 1 || this.ogl.mode === 2 || (this.ogl.mode === 5 && this.ogl.db.options.expeditionRedirect))
{
//localStorage.setItem('ogl-redirect', this.ogl.nextRedirection);
//window.location.href = this.ogl.nextRedirection;
this.ogl._shortcut.redirectToPlanet(1);
}
else if(this.ogl.mode === 5)
{
this.ogl._shortcut.redirectToPlanet(0);
}
else if(this.ogl.mode === 3 && this.ogl.cache.toSend)
{
let cumul = [0,0,0];
let urlParams = new URLSearchParams(window.location.search);
if(urlParams.get('substractMode') && urlParams.get('targetid'))
{
const targetID = urlParams.get('targetid');
cumul[0] -= (this.ogl.db.myPlanets[targetID]?.metal || 0);
cumul[1] -= (this.ogl.db.myPlanets[targetID]?.crystal || 0);
cumul[2] -= (this.ogl.db.myPlanets[targetID]?.deut || 0);
}
this.ogl.cache.toSend.forEach(build =>
{
const id = new URLSearchParams(window.location.search).get('targetid');
const cost = this.ogl.db.myPlanets[id].todolist[build.id][build.level].cost;
for(let i=0; i<3; i++)
{
let res = i === 2 ? 'deut' : i === 1 ? 'crystal' : 'metal';
let cargo = i == 2 ? 'cargoDeuterium' : i == 1 ? 'cargoCrystal' : 'cargoMetal';
let newVal = Math.min(fleetDispatcher[cargo] - cumul[i], build.cost[res]);
cumul[i] += newVal;
cost[res] -= newVal;
}
if(build.amount && cost.metal + cost.crystal + cost.deut <= 0) delete this.ogl.db.myPlanets[id].todolist[build.id][build.level];
if(Object.values(this.ogl.db.myPlanets[id].todolist[build.id]).length < 1)
{
delete this.ogl.db.myPlanets[id].todolist[build.id];
}
});
window.location.href = defaultRedirection;
}
else if(this.ogl.mode === 4)
{
// save report state (spy table quick raid)
// prevent to duplicate position when spamming too quick
const messageID = parseInt(new URLSearchParams(window.location.search).get('oglmsg')) || 0;
this.ogl._message.initMessageDB();
if(this.ogl._message.messageDB[messageID])
{
this.ogl._message.messageDB[messageID].isAttacked = 1;
this.ogl._message.saveMessagesDB();
}
window.location.href = this.ogl._shortcut.getRedirectionLink({ component:'messages' });
}
else
{
window.location.href = defaultRedirection;
}
this.ogl.save();
}
addLimiters()
{
// add limiters
const limiterContainer = this.ogl._dom.component;
const limiterField = Util.addDom('fieldset', { parent:limiterContainer });
Util.addDom('legend', { parent:limiterField, child:'<i class="material-icons">settings</i> Settings' });
const limitResourceLabel = Util.addDom('label', { class:'ogl_limiterLabel tooltip', 'data-limiter-type':'resource', title:this.ogl._lang.find('resourceLimiter'), parent:limiterField, child:'Limit resources' });
const limitResourceCheckbox = Util.addDom('input', { type:'checkbox', parent:limitResourceLabel, onclick:() =>
{
this.ogl.db.fleetLimiter.resourceActive = !this.ogl.db.fleetLimiter.resourceActive;
this.updateLimiter();
}});
const limitShipLabel = Util.addDom('label', { class:'ogl_limiterLabel tooltip', 'data-limiter-type':'ship', title:this.ogl._lang.find('fleetLimiter'), parent:limiterField, child:'Limit ships' });
const limitShipCheckbox = Util.addDom('input', { type:'checkbox', parent:limitShipLabel, onclick:() =>
{
this.ogl.db.fleetLimiter.shipActive = !this.ogl.db.fleetLimiter.shipActive;
this.updateLimiter();
}});
const limitFoodLabel = Util.addDom('label', { class:'ogl_limiterLabel tooltip', title:this.ogl._lang.find('forceIgnoreFood'), parent:limiterField, child:'Ignore Food' });
const limitFoodCheckbox = Util.addDom('input', { type:'checkbox', parent:limitFoodLabel, onclick:() =>
{
this.ogl.db.fleetLimiter.ignoreFood = !this.ogl.db.fleetLimiter.ignoreFood;
this.updateLimiter();
}});
const keepLabel = Util.addDom('div', { class:'ogl_limiterGroup tooltip', title:this.ogl._lang.find('forceKeepCapacity'), parent:limiterField, child:'Locked <i class="material-icons">blocked</i>' });
[202, 203, 219, 200].forEach(shipID =>
{
const item = Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, parent:keepLabel, onclick:() =>
{
keepLabel.querySelector('.ogl_active')?.classList.remove('ogl_active');
item.classList.add('ogl_active');
this.ogl.db.keepEnoughCapacityShip = shipID;
this.updateLimiter();
}});
if(this.ogl.db.keepEnoughCapacityShip == shipID) item.classList.add('ogl_active');
});
if(this.ogl.db.fleetLimiter.resourceActive) limitResourceCheckbox.checked = true;
if(this.ogl.db.fleetLimiter.shipActive) limitShipCheckbox.checked = true;
if(this.ogl.db.fleetLimiter.ignoreFood) limitFoodCheckbox.checked = true;
this.updateLimiter();
}
updateLimiter()
{
if(!unsafeWindow.fleetDispatcher) return;
const dataKey = this.ogl.currentPlanet.obj.type == 'moon' ? 'moonData' : 'data';
this.totalCapacity = 0;
// ships
fleetDispatcher.shipsOnPlanet.forEach((entry, index) =>
{
let forced = 0;
if(this.ogl.db.keepEnoughCapacityShip == entry.id && this.ogl.mode !== 1 && this.ogl.mode !== 2)
{
forced = this.shipsForResources(entry.id);
}
if(this.ogl.db.fleetLimiter.shipActive && this.ogl.db.fleetLimiter[dataKey][entry.id]) entry.number = Math.max(0, this.initialShipsOnPlanet.find(e => e.id == entry.id).number - Math.max(this.ogl.db.fleetLimiter[dataKey][entry.id], forced));
else entry.number = this.initialShipsOnPlanet.find(e => e.id == entry.id).number - forced;
if(fleetDispatcher.shipsToSend.find(e => e.id == entry.id)?.number >= entry.number)
{
fleetDispatcher.selectShip(entry.id, entry.number);
}
const techDom = document.querySelector(`[data-technology="${entry.id}"]`);
if(techDom)
{
techDom.querySelector('.ogl_maxShip')?.remove();
const text = Util.addDom('div', { class:'ogl_maxShip', parent:techDom });
text.innerHTML = `<b>-${Util.formatToUnits(this.ogl.db.fleetLimiter.shipActive ? Math.max(this.ogl.db.fleetLimiter[dataKey][entry.id], forced) : forced)}</b>`;
text.addEventListener('click', () => { Util.runAsync(() => this.ogl._ui.openFleetProfile()).then(e => this.ogl._popup.open(e)); });
if(!this.ogl.db.fleetLimiter.shipActive && this.ogl.db.keepEnoughCapacityShip != entry.id) text.classList.add('ogl_hidden');
if(entry.number <= 0)
{
techDom.classList.add('ogl_notEnough');
fleetDispatcher.removeShip(entry.id);
}
else techDom.classList.remove('ogl_notEnough');
this.totalCapacity += this.ogl.db.shipsCapacity[entry.id] * entry.number;
//techDom.querySelector('input').classList.add('ogl_inputCheck');
}
document.querySelectorAll(`.ogl_flashNotEnough`).forEach(e => { if(e.value == 0) e.classList.remove('ogl_flashNotEnough') });
});
// resources
['metal', 'crystal', 'deut', 'food'].forEach(resourceName =>
{
if(this.ogl.db.fleetLimiter.resourceActive)
{
fleetDispatcher[this.resOnPlanet[resourceName]] = Math.max(0, this.initialResOnPlanet[resourceName] - (this.ogl.db.fleetLimiter[dataKey][resourceName] || 0));
}
else
{
fleetDispatcher[this.resOnPlanet[resourceName]] = Math.max(0, this.initialResOnPlanet[resourceName]);
}
if(resourceName == 'food' && this.ogl.db.fleetLimiter.ignoreFood) fleetDispatcher[this.resOnPlanet[resourceName]] = 0;
fleetDispatcher[this.cargo[resourceName]] = Math.min(fleetDispatcher[this.cargo[resourceName]], fleetDispatcher[this.resOnPlanet[resourceName]]);
const techDom = document.querySelector(`#fleet2 #resources .${resourceName?.replace('deut', 'deuterium')}`);
if(techDom)
{
techDom.querySelector('.ogl_maxShip')?.remove();
const text = Util.addDom('div', { class:'ogl_maxShip', parent:techDom });
text.innerHTML = `<b>-${Util.formatToUnits(this.ogl.db.fleetLimiter.resourceActive ? this.ogl.db.fleetLimiter[dataKey][resourceName] : 0, 0)}</b>`;
text.addEventListener('click', () => { Util.runAsync(() => this.ogl._ui.openFleetProfile()).then(e => this.ogl._popup.open(e)); });
techDom.parentNode.querySelector('input').classList.add('ogl_inputCheck');
}
});
fleetDispatcher.refresh();
this.updateRequiredShips();
initTooltips();
}
reverseShip(shipID)
{
const delta = fleetDispatcher.shipsOnPlanet.find(e => e.id == shipID)?.number - (fleetDispatcher.findShip(shipID)?.number || 0);
fleetDispatcher.selectShip(shipID, delta);
fleetDispatcher.refresh();
}
reverseResources(icon)
{
let type = icon.classList.contains('metal') ? 'metal' : icon.classList.contains('crystal') ? 'crystal' : icon.classList.contains('deuterium') ? 'deut' : 'food';
fleetDispatcher[this.cargo[type]] = Math.min(fleetDispatcher[this.resOnPlanet[type]] - fleetDispatcher[this.cargo[type]], fleetDispatcher.getFreeCargoSpace());
fleetDispatcher.refresh();
}
favShip(shipID)
{
this.ogl.db.options.defaultShip = shipID;
if(this.ogl.db.currentSide == 'settings')
{
this.ogl.fretShips.forEach(sID =>
{
document.querySelector(`.ogl_config [data-opt="defaultShip"] .ogl_${sID}`).classList.remove('ogl_active');
if(sID == shipID) document.querySelector(`.ogl_config [data-opt="defaultShip"] .ogl_${sID}`).classList.add('ogl_active');
});
}
this.ogl.fretShips.forEach(sID =>
{
this.ogl._dom.tech[sID]._ogl.fav.classList.add('ogl_grayed');
});
this.ogl._dom.tech[shipID]._ogl.fav.classList.remove('ogl_grayed');
this.updateLimiter();
if(this.ogl.mode === 1 || this.ogl.mode === 2)
{
this.ogl.fretShips.forEach(sID => fleetDispatcher.selectShip(sID, 0));
fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, this.shipsForResources());
fleetDispatcher.selectMaxAll();
}
else if(this.ogl.mode === 3 && this.ogl.cache.toSend)
{
this.ogl.fretShips.forEach(sID => fleetDispatcher.selectShip(sID, 0));
this.prefillTodolistCargo();
}
}
lockShip(shipID)
{
this.ogl.db.keepEnoughCapacityShip = this.ogl.db.keepEnoughCapacityShip == shipID ? 200 : shipID;
Object.values(this.ogl._dom.tech).forEach(tech =>
{
if(tech._ogl.lock)
{
if(tech._ogl.id == this.ogl.db.keepEnoughCapacityShip) tech._ogl.lock.classList.remove('ogl_grayed');
else tech._ogl.lock.classList.add('ogl_grayed');
}
});
document.querySelectorAll('.ogl_limiterGroup .ogl_active').forEach(e => e.classList.remove('ogl_active'));
document.querySelector(`.ogl_limiterGroup .ogl_${this.ogl.db.keepEnoughCapacityShip}`).classList.add('ogl_active');
this.updateLimiter();
}
updateRequiredShips()
{
const fragment = document.createDocumentFragment();
this.ogl.fretShips.forEach(shipID =>
{
const amount = this.shipsForResources(shipID);
const item = Util.addDom('div', { class:`tooltip ogl_required ogl_icon ogl_${shipID}`, title:Util.formatNumber(amount), parent:fragment, child:Util.formatToUnits(amount), onclick:() =>
{
fleetDispatcher.selectShip(shipID, amount);
fleetDispatcher.selectMaxAll();
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
}});
if((fleetDispatcher.shipsOnPlanet.find(e => e.id == shipID)?.number || 0) < amount) item.classList.add('ogl_notEnough');
});
this.ogl._dom.redraw(this.ogl._dom.requiredShips, fragment);
fleetDispatcher.shipsOnPlanet.forEach(entry =>
{
const shipID = entry.id;
const domElement = this.ogl._dom.technology[shipID];
if(!domElement) return;
const shipFlag = domElement._ogl.shipFlag;
shipFlag.innerText = '';
});
if(!document.querySelector('.ogl_popup.ogl_active')) fleetDispatcher.focusSubmitFleet1();
}
shipsForResources(shipID, resource)
{
shipID = shipID || this.ogl.db.options.defaultShip;
resource = resource === 0 ? 0 : (resource || -1);
if(resource === -1)
{
if(unsafeWindow.fleetDispatcher)
{
['metal', 'crystal', 'deut', 'food'].forEach(resourceName => resource += fleetDispatcher[this.resOnPlanet[resourceName]]);
}
else
{
['metal', 'crystal', 'deut', 'food'].forEach(resourceName => resource += this.ogl.currentPlanet?.obj?.[resourceName]) || 0;
}
}
return Math.ceil(resource / this.ogl.db.shipsCapacity[shipID]) || 0;
}
selectExpedition(shipID)
{
if(fleetDispatcher.fetchTargetPlayerDataTimeout) return;
this.ogl.mode = 5;
fleetDispatcher.resetShips();
fleetDispatcher.resetCargo();
const coords = [fleetDispatcher.currentPlanet.galaxy, fleetDispatcher.currentPlanet.system, fleetDispatcher.currentPlanet.position];
const factor = { 202:1, 203:3, 219:5.75 };
const expeditionData = this.ogl.calcExpeditionMax();
//const maxResources = this.ogl.db.options.expeditionValue || base * (1 + (cumul[14205] + cumul[14211])) * (1 + cumul[14218]);
//const maxResources = this.ogl.db.options.expeditionValue || (this.ogl.account.class == 3 ? treshold.max * 3 * this.ogl.server.economySpeed : treshold.max * 2) * (1 + LFbonus / 100);
const amount = Math.max(this.ogl.db.options.expeditionValue ? 0 : Math.ceil(expeditionData.threshold.base / factor[shipID]), this.shipsForResources(shipID, expeditionData.max));
let fillerID = 0;
[218, 213, 211, 215, 207, 206, 205, 204].forEach(filler =>
{
if(this.ogl.db.options.expeditionBigShips.indexOf(filler) >= 0 && fillerID == 0 && document.querySelector(`.technology[data-technology="${filler}"] .amount`)?.getAttribute('data-value') > 0) fillerID = filler;
});
fleetDispatcher.shipsOnPlanet.forEach(ship =>
{
if(ship.id == shipID) fleetDispatcher.selectShip(ship.id, amount);
else if(ship.id == fillerID && shipID != fillerID) fleetDispatcher.selectShip(ship.id, 1);
else if(ship.id == 210) fleetDispatcher.selectShip(ship.id, 1);
else if(ship.id == 219 && shipID != 219) fleetDispatcher.selectShip(ship.id, 1);
});
let randomSystem = coords[1];
if(this.ogl.db.options.expeditionRandomSystem)
{
do
{
randomSystem = Math.round(Math.random() * this.ogl.db.options.expeditionRandomSystem) * (Math.round(Math.random()) ? 1 : -1) + coords[1];
if(randomSystem >= 500) randomSystem = randomSystem - 499;
if(randomSystem <= -1) randomSystem = 499 - randomSystem;
}
while(randomSystem === coords[1]);
}
this.setRealTarget(fleetDispatcher.realTarget,
{
galaxy:coords[0],
system:randomSystem,
position:16,
type:1,
name:fleetDispatcher.loca.LOCA_EVENTH_ENEMY_INFINITELY_SPACE
});
fleetDispatcher.selectMission(15);
fleetDispatcher.expeditionTime = 1;
fleetDispatcher.updateExpeditionTime();
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
this.ogl.db.lastExpeditionShip = shipID;
}
updateSpeedBar()
{
// update speed selector
document.querySelector('#speedPercentage').addEventListener('mousemove', event =>
{
document.querySelector('#speedPercentage').querySelectorAll('.selected').forEach(e => e.classList.remove('selected'));
document.querySelector('#speedPercentage').querySelector(`[data-step="${fleetDispatcher.realSpeedPercent}"]`).classList.add('selected');
});
document.querySelector('#speedPercentage').addEventListener('click', e =>
{
// fix OGame bug for ff mobile
if(e.target.getAttribute('data-step'))
{
document.querySelector('#speedPercentage .bar').style.width = e.target.offsetLeft + e.target.offsetWidth + 'px';
document.querySelector('#speedPercentage').querySelectorAll('.selected').forEach(e => e.classList.remove('selected'));
e.target.classList.add('selected');
fleetDispatcher.speedPercent = e.target.getAttribute('data-step');
fleetDispatcher.realSpeedPercent = e.target.getAttribute('data-step');
fleetDispatcher.refresh();
}
fleetDispatcher.realSpeedPercent = fleetDispatcher.speedPercent;
fleetDispatcher.setFleetPercent(fleetDispatcher.speedPercent);
if(fleetDispatcher.cargoDeuterium + fleetDispatcher.getConsumption() >= fleetDispatcher.getDeuteriumOnPlanetWithoutConsumption())
{
fleetDispatcher.cargoDeuterium = 0;
fleetDispatcher.selectMaxDeuterium();
fleetDispatcher.refresh();
}
fleetDispatcher.focusSendFleet();
});
}
prefillTodolistCargo()
{
let cumul = 0;
let curmulRes = [0,0,0];
let max = 0;
let maxRes = [0, 0, 0];
this.ogl.cache.toSend.forEach(build =>
{
curmulRes[0] = curmulRes[0] + build.cost.metal;
curmulRes[1] = curmulRes[1] + build.cost.crystal;
curmulRes[2] = curmulRes[2] + build.cost.deut;
});
maxRes[0] = Math.min(fleetDispatcher.metalOnPlanet, curmulRes[0]);
maxRes[1] = Math.min(fleetDispatcher.crystalOnPlanet, curmulRes[1]);
maxRes[2] = Math.min(fleetDispatcher.deuteriumOnPlanet, curmulRes[2]);
max = maxRes[0] + maxRes[1] + maxRes[2];
let urlParams = new URLSearchParams(window.location.search);
if(urlParams.get('substractMode') && urlParams.get('targetid'))
{
const targetID = urlParams.get('targetid');
curmulRes[0] = Math.max(curmulRes[0] - (this.ogl.db.myPlanets[targetID]?.metal || 0), 0);
curmulRes[1] = Math.max(curmulRes[1] - (this.ogl.db.myPlanets[targetID]?.crystal || 0), 0);
curmulRes[2] = Math.max(curmulRes[2] - (this.ogl.db.myPlanets[targetID]?.deut || 0), 0);
}
cumul = curmulRes[0] + curmulRes[1] + curmulRes[2];
fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, this.shipsForResources(this.ogl.db.options.defaultShip, Math.min(cumul, max)));
if(fleetDispatcher.shipsToSend.length > 0)
{
fleetDispatcher.cargoMetal = Math.min(curmulRes[0], fleetDispatcher.metalOnPlanet);
fleetDispatcher.cargoCrystal = Math.min(curmulRes[1], fleetDispatcher.crystalOnPlanet);
fleetDispatcher.cargoDeuterium = Math.min(curmulRes[2], fleetDispatcher.deuteriumOnPlanet);
fleetDispatcher.refresh();
}
}
sendNextMiniFleet()
{
if(this.miniFleetQueue.length < 1) return;
const item = this.miniFleetQueue[0];
const params =
{
mission:item.order,
galaxy:item.galaxy,
system:item.system,
position:item.position,
type:item.type,
shipCount:item.ships || this.ogl.db.spyProbesCount,
token:token,
uid:item.uid,
popup:item.popup
};
if(item.additionalParams && typeof item.additionalParams === 'object')
{
Object.keys(item.additionalParams).map(key =>
{
if(!params[key]) params[key] = item.additionalParams[key];
});
}
$.ajax(miniFleetLink,
{
data:params,
dataType:"json",
type:"POST"
});
}
updateSpyFunctions()
{
sendShips = (order, galaxy, system, planet, planettype, shipCount, additionalParams, popup) =>
{
const item = {};
item.order = order;
item.galaxy = galaxy;
item.system = system;
item.position = planet;
item.type = planettype;
item.ships = shipCount;
item.additionalParams = additionalParams;
item.retry = 0;
item.uid = crypto.randomUUID();
item.popup = popup || false;
document.querySelectorAll(`[onclick*="sendShips(${order}, ${galaxy}, ${system}, ${planet}, ${planettype}"]:not([data-spy-coords])`).forEach(e =>
{
e.setAttribute('data-spy-coords', `${galaxy}:${system}:${planet}:${planettype}`);
});
document.querySelectorAll(`[data-spy-coords="${galaxy}:${system}:${planet}:${planettype}"]`).forEach(e => e.setAttribute('data-spy', 'prepare'));
const shouldSend = this.miniFleetQueue.length < 1;
this.miniFleetQueue.push(item);
if(shouldSend) this.sendNextMiniFleet();
}
sendShipsWithPopup = (order, galaxy, system, planet, planettype, shipCount, additionalParams) =>
{
sendShips(order, galaxy, system, planet, planettype, shipCount, additionalParams, true);
}
}
checkSendShips()
{
// spy
document.querySelectorAll(`[onclick*="sendShips(6"]:not([data-spy-coords]), [onclick*="sendShipsWithPopup(6"]:not([data-spy-coords])`).forEach(element =>
{
const matches = element.getAttribute('onclick').match(/(?<=sendShips[WithPopup]*?\()(.*?)(?=\))/);
if(matches)
{
const params = matches[0].match(/\d+/g)
element.setAttribute('data-spy-coords', `${params[1]}:${params[2]}:${params[3]}:${params[4]}`);
const lastSpy = this.ogl.db.pdb[`${params[1]}:${params[2]}:${params[3]}`]?.spy?.[params[4] == 1 ? 0 : 1] || 0;
if(serverTime.getTime() - lastSpy < this.ogl.db.options.spyIndicatorDelay)
{
element.setAttribute('data-spy', 'recent');
}
}
});
// df
document.querySelectorAll(`[onclick*="sendShips(8"]:not([data-spy-coords]), [onclick*="sendShipsWithPopup(8"]:not([data-spy-coords])`).forEach(element =>
{
const matches = element.getAttribute('onclick').match(/[sendShips|sendShipsWithPopup]\((\d|,| )+\)/);
if(matches)
{
const params = matches[0].match(/\d+/g)
element.setAttribute('data-spy-coords', `${params[1]}:${params[2]}:${params[3]}:${params[4]}`);
}
});
}
updateSystemSpy()
{
const self = this;
document.querySelector('.spysystemlink').addEventListener('click', event =>
{
event.preventDefault();
event.stopPropagation();
const shortcutButton = document.querySelector('[data-key-id="galaxySpySystem"]');
const targetUrl = event.target.getAttribute('data-target-url');
if(!targetUrl) return;
let hasError = false;
shortcutButton?.setAttribute('data-spy', 'prepare');
$.post(targetUrl,
{
galaxy:$("#galaxy_input").val(),
system:$("#system_input").val(),
token:token
}, 'json')
.done(function(json)
{
const data = JSON.parse(json);
token = data.newAjaxToken;
updateOverlayToken('phalanxDialog', data.newAjaxToken);
updateOverlayToken('phalanxSystemDialog', data.newAjaxToken);
if(!data.count)
{
self.ogl._notification.addToQueue(data.text, false);
hasError = true;
}
data.planets.forEach(params =>
{
document.querySelectorAll(`[data-spy-coords="${params.galaxy}:${params.system}:${params.position}:${params.type}"]`).forEach(e => e.setAttribute('data-spy', 'done'));
if(self.ogl.db.pdb[`${params.galaxy}:${params.system}:${params.position}`])
{
self.ogl.db.pdb[`${params.galaxy}:${params.system}:${params.position}`].spy = self.ogl.db.pdb[`${params.galaxy}:${params.system}:${params.position}`].spy || [];
if(params.type == 1)
{
self.ogl.db.pdb[`${params.galaxy}:${params.system}:${params.position}`].spy[0] = serverTime.getTime();
}
else
{
self.ogl.db.pdb[`${params.galaxy}:${params.system}:${params.position}`].spy[1] = serverTime.getTime();
}
}
});
if(hasError) shortcutButton?.setAttribute('data-spy', 'fail');
else shortcutButton?.setAttribute('data-spy', 'done');
});
});
}
}
class GalaxyManager extends Manager
{
init()
{
if(!this.isReady)
{
this.isReady = true;
this.unloadSystem();
submitForm();
}
}
load()
{
if(this.ogl.page != 'galaxy' || !unsafeWindow.galaxy) return;
this.galaxy = galaxy;
this.system = system;
const loader = document.querySelector('#galaxyLoading');
loader.setAttribute('data-currentposition', this.galaxy+':'+this.system);
Util.overWrite('loadContentNew', unsafeWindow, (g, s) =>
{
this.unloadSystem();
loader.setAttribute('data-currentPosition', `${g}:${s}`);
tippy.hideAll();
});
submitForm();
this.ogl._fleet.updateSystemSpy();
}
check(data)
{
if(!data.success || !data.system)
{
this.ogl._notification.addToQueue(`Error, cannot fetch [${this.galaxy}:${this.system}] data`);
return;
}
let isEmpty = true;
this.galaxy = data.system.galaxy;
this.system = data.system.system;
galaxy = this.galaxy;
system = this.system;
document.querySelector('#galaxy_input').value = this.galaxy;
document.querySelector('#system_input').value = this.system;
let ptrePositions = {}; // ptre positions data
let ptreActivities = {}; // ptre activities data
this.ogl.db.spyProbesCount = data.system.settingsProbeCount || 0;
let getActivity = element =>
{
if(element.activity.showActivity == 15) return '*'; // acti
else return element.activity.idleTime || 60;
}
data.system.galaxyContent.forEach(line =>
{
const position = line.position;
const debris = { metal:0, crystal:0, deut:0, total:0 };
const row = document.querySelector(`#galaxyRow${position}`);
if(position == 16)
{
debris.metal = parseInt(line.planets.resources.metal.amount);
debris.crystal = parseInt(line.planets.resources.crystal.amount);
debris.deut = parseInt(line.planets.resources.deuterium.amount);
debris.total = debris.metal + debris.crystal + debris.deut;
this.updateDebrisP16(debris, row);
return;
}
const coords = `${this.galaxy}:${this.system}:${position}`;
const playerID = parseInt(line.player.playerId == 99999 ? -1 : line.player.playerId);
const playerName = line.player.playerName;
const playerStatus = Array.from(row.querySelector(`.cellPlayerName span[class*="status_"]`)?.classList || []).filter(e => e.startsWith('status_'))[0];
const playerStatusTag = this.ogl.playerStatus.find(e => e.class == playerStatus)?.defaultTag || 'n';
//const playerStatusTag = line.player.isOnVacation ? 'v' : line.player.isLongInactive ? 'I' : line.player.isInactive ? 'i' : 'n';
const isOwn = playerID == this.ogl.account.id;
const rank = line.player.highscorePositionPlayer;
const activities = [];
let planetID = -1;
let moonID = -1;
let moonSize = -1;
row.querySelector('.cellDebris').classList.remove('ogl_important');
line.planets.forEach(element =>
{
if(element.planetType == 1) // planet
{
activities[0] = getActivity(element);
planetID = element.isDestroyed ? -1 : parseInt(element.planetId);
if(!line.player.isInactive) isEmpty = false;
}
else if(element.planetType == 2) // debris
{
debris.metal = parseInt(element.resources.metal.amount);
debris.crystal = parseInt(element.resources.crystal.amount);
debris.deut = parseInt(element.resources.deuterium.amount);
debris.total = debris.metal + debris.crystal + debris.deut;
this.updateDebris(debris, row);
}
else if(element.planetType == 3) // moon
{
activities[1] = getActivity(element);
moonID = element.isDestroyed ? -1 : parseInt(element.planetId);
moonSize = parseInt(element.size);
}
});
if(line.player.isAdmin) return;
const oldEntry = this.ogl.db.pdb[coords] || { pid:-1, mid:-1 };
if(this.ogl.ptreKey)
{
ptrePositions[coords] = {};
ptrePositions[coords].teamkey = this.ogl.ptreKey;
ptrePositions[coords].galaxy = this.galaxy;
ptrePositions[coords].system = this.system;
ptrePositions[coords].position = position;
ptrePositions[coords].timestamp_ig = serverTime.getTime();
ptrePositions[coords].old_player_id = oldEntry.uid || -1;
ptrePositions[coords].timestamp_api = oldEntry?.api || -1;
ptrePositions[coords].old_name = oldEntry?.name || false;
ptrePositions[coords].old_rank = oldEntry?.score?.globalRanking || -1;
ptrePositions[coords].old_score = oldEntry?.score?.global || -1;
ptrePositions[coords].old_fleet = oldEntry?.score?.military || -1;
if(playerID < 0 && oldEntry.pid != planetID) // old:occupied -> now:empty
{
ptrePositions[coords].id = -1;
ptrePositions[coords].player_id = -1;
ptrePositions[coords].name = false;
ptrePositions[coords].rank = -1;
ptrePositions[coords].score = -1;
ptrePositions[coords].fleet = -1;
ptrePositions[coords].status = false;
ptrePositions[coords].moon = { id:-1 };
}
else if(playerID < 0) // old:empty -> now:empty
{
delete ptrePositions[coords];
}
}
// planet has changed
if(oldEntry.pid != planetID)
{
this.ogl.removeOldPlanetOwner(coords, playerID);
delete this.ogl.db.pdb[coords];
}
// valid player
if(playerID > 0)
{
this.ogl.db.pdb[coords] = this.ogl.db.pdb[coords] || {};
const player = this.ogl.db.udb[playerID] || this.ogl.createPlayer(playerID);
const planet = this.ogl.db.pdb[coords];
if(this.ogl.ptreKey && (oldEntry.pid != planetID || (oldEntry.mid || -1) != moonID)) // planet or moon has changed
{
ptrePositions[coords].id = planetID;
ptrePositions[coords].player_id = playerID;
ptrePositions[coords].name = playerName || false;
ptrePositions[coords].rank = rank || -1;
ptrePositions[coords].score = player.score?.global || -1;
ptrePositions[coords].fleet = player.score?.military || -1;
ptrePositions[coords].status = playerStatusTag;
if(moonID > -1)
{
ptrePositions[coords].moon = {};
ptrePositions[coords].moon.id = moonID;
ptrePositions[coords].moon.size = moonSize;
}
console.log(`${coords} | ${oldEntry.pid} -> ${planetID} | ${oldEntry.mid} -> ${moonID}`)
}
else // no change
{
delete ptrePositions[coords];
}
// update planet data
planet.uid = playerID;
planet.pid = planetID;
planet.mid = moonID;
planet.coo = coords;
// update player data
player.uid = playerID;
player.name = playerName;
player.status = playerStatusTag;
player.liveUpdate = serverTime.getTime();
player.score = player.score || {};
player.score.globalRanking = rank;
player.planets = player.planets || [];
if(player.planets.indexOf(coords) < 0) player.planets.push(coords);
this.updateRow(player, row, isOwn, coords);
// get the activities if the player has been pinned
if((player.pin || this.ogl.db.lastPinnedList.indexOf(playerID) > -1) && this.ogl.db.pdb[coords])
{
this.ogl.db.pdb[coords].api = serverTime.getTime();
this.ogl.db.pdb[coords].acti = [activities[0], activities[1], serverTime.getTime()];
this.ogl.db.pdb[coords].debris = debris.total;
if(document.querySelector('.ogl_side.ogl_active') && this.ogl.db.currentSide == playerID) this.ogl._topbar.openPinnedDetail(playerID);
if(this.ogl.ptreKey)
{
ptreActivities[coords] = {};
ptreActivities[coords].id = planetID;
ptreActivities[coords].player_id = playerID;
ptreActivities[coords].teamkey = this.ogl.ptreKey;
ptreActivities[coords].mv = playerStatusTag == 'v' ? true : false;
ptreActivities[coords].activity = activities[0];
ptreActivities[coords].galaxy = this.galaxy;
ptreActivities[coords].system = this.system;
ptreActivities[coords].position = position;
ptreActivities[coords].main = this.ogl.db.pdb[coords].home || false;
ptreActivities[coords].cdr_total_size = debris.total;
if(moonID > -1)
{
ptreActivities[coords].moon = {};
ptreActivities[coords].moon.id = moonID;
ptreActivities[coords].moon.activity = activities[1];
}
}
}
}
});
// send positions data to the PTRE server
if(Object.keys(ptrePositions).length > 0) this.ogl.PTRE.postPositions(ptrePositions);
// send acivities data to the PTRE server
if(Object.keys(ptreActivities).length > 0) this.ogl.PTRE.postActivities(ptreActivities);
// update galaxy bottom bar
const galaxyMoreInfo = document.querySelector('.ctGalaxyFooter .ogl_moreGalaxyInfo') || Util.addDom('div', { class:'ogl_moreGalaxyInfo' });
galaxyMoreInfo.innerText = '';
const timeObj = this.ogl._time.getObj();
const discovery = Util.addDom('div', { class:'ogl_lastDiscovery tooltip', title:'Last discovery', 'data-galaxy':this.ogl.db.lastDiscovery || '1:1', parent:galaxyMoreInfo, child:`<i class="material-icons">genetics</i>${this.ogl.db.lastDiscovery || '?'}` });
Util.addDom('div', { class:'ogl_separator', parent:galaxyMoreInfo });
const empty = Util.addDom('div', { class:'ogl_systemState material-icons tooltip', parent:galaxyMoreInfo });
Util.addDom('div', { class:'ogl_separator', parent:galaxyMoreInfo });
const refresh = Util.addDom('div', { class:'ogl_lastGalaxyRefresh tooltip', parent:galaxyMoreInfo, title:'Last galaxy refresh', child:'<span class="material-icons">schedule</span>' });
requestAnimationFrame(() =>
{
refresh.appendChild(this.ogl._time.convertTimestampToDate(this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server));
if(this.ogl.db.lastDiscovery) discovery.classList.remove('ogl_hidden');
empty.innerText = 'person_cancel';
empty.title = isEmpty ? 'This system is "empty"' : 'This system is NOT "empty"';
isEmpty ? empty.classList.add('ogl_danger') : empty.classList.remove('ogl_danger');
if(!galaxyMoreInfo.parentElement)
{
document.querySelector('.ctGalaxyFooter #colonized').appendChild(galaxyMoreInfo);
}
this.checkCurrentSystem();
});
}
updateRow(player, row, isOwn, coords)
{
const page = Math.max(1, Math.ceil(player.score.globalRanking / 100));
this.ogl._ui.turnIntoPlayerLink(player.uid, row.querySelector('.cellPlayerName [class*="status_abbr"]'), player.name, player.status);
Util.addDom('a', { class:'ogl_ranking', parent:row.querySelector('.cellPlayerName'), href:`https://${window.location.host}/game/index.php?page=highscore&site=${page}&searchRelId=${player.uid}`, child:'#'+player.score.globalRanking });
if(!isOwn)
{
this.ogl._ui.addPinButton(row.querySelector('.cellPlayerName'), player.uid);
this.ogl._ui.addTagButton(row.querySelector('.cellPlanetName'), coords);
}
if(player.uid == this.ogl.db.currentSide)
{
row.querySelector('.cellPlayerName').classList.add('ogl_active');
}
}
updateDebris(debris, row)
{
if(debris.total > 0)
{
const dom = row.querySelector('.microdebris');
dom.classList.remove('debris_1');
const ships = dom.querySelector('[onclick*="sendShips(8"]');
const div = Util.addDom('div', { parent:dom });
if(ships)
{
const params = ships.getAttribute('onclick').match(/\d+/g).map(Number);
div.setAttribute('data-spy-coords', `${params[1]}:${params[2]}:${params[3]}:2`);
div.addEventListener('click', () => sendShips(params[0], params[1], params[2], params[3], params[4], params[5]));
}
div.innerHTML = Util.formatToUnits(debris.total, 0);
if(debris.total >= this.ogl.db.options.resourceTreshold)
{
div.closest('.cellDebris').classList.add('ogl_important');
}
}
}
updateDebrisP16(debris, row)
{
if(debris.total > 0)
{
let content = row.querySelectorAll('.ListLinks li');
if(!content[0]) content = document.querySelectorAll('#debris16 .ListLinks li');
let scouts = content[3];
let action = content[4];
(document.querySelector('.expeditionDebrisSlotBox .ogl_expeditionRow') || Util.addDom('div', { class:'ogl_expeditionRow', parent:document.querySelector('.expeditionDebrisSlotBox') })).innerHTML = `
<div>
<div class="material-icons">debris</div>
</div>
<div class="ogl_expeditionDebris">
<div class="ogl_icon ogl_metal">${Util.formatToUnits(debris.metal)}</div>
<div class="ogl_icon ogl_crystal">${Util.formatToUnits(debris.crystal)}</div>
<div class="ogl_icon ogl_deut">${Util.formatToUnits(debris.deut)}</div>
<div class="ogl_expeditionText">${scouts.innerText}</div>
<div class="ogl_expeditionText">${action.outerHTML}</div>
</div>
`;
if(debris.total >= this.ogl.db.options.resourceTreshold) document.querySelector('.ogl_expeditionRow').classList.add('ogl_important');
}
row.classList.remove('ogl_hidden');
}
unloadSystem()
{
if(document.querySelector('#galaxyRow16'))
{
//if(document.querySelector('.ogl_expeditionRow')) document.querySelector('.ogl_expeditionRow').innerText = '';
document.querySelector('.ogl_expeditionRow') && document.querySelector('.ogl_expeditionRow').remove();
document.querySelector('#galaxyRow16').classList.remove('ogl_important');
}
for(let i=1; i<16; i++)
{
document.querySelectorAll(`#galaxyRow${i} .galaxyCell:not(.cellPosition)`).forEach(e =>
{
e.innerText = '';
e.classList.remove('ogl_important');
e.classList.remove('ogl_active');
});
document.querySelector(`#galaxyRow${i}`).className = 'galaxyRow ctContentRow empty_filter filtered_filter_empty';
}
}
checkCurrentSystem()
{
document.querySelectorAll('[data-galaxy]').forEach(element =>
{
let coords = element.getAttribute('data-galaxy').split(':');
if(this.galaxy == coords[0] && this.system == coords[1]) element.classList.add('ogl_active');
else element.classList.remove('ogl_active');
});
if(this.ogl._tooltip) this.ogl._tooltip.initTooltipList(document.querySelectorAll('#galaxyContent .tooltipClick, #galaxyContent .ownPlayerRow, .ogl_moreGalaxyInfo .tooltip'));
//initTooltips();
this.ogl._fleet.checkSendShips();
}
}
class JumpgateManager extends Manager
{
load()
{
this.initialRel = {};
Util.overWrite('initJumpgate', unsafeWindow, false, () =>
{
this.check();
});
Util.overWrite('initPhalanx', unsafeWindow, false, () =>
{
this.checkPhalanx();
});
this.saveTimer();
this.displayTimer();
}
check()
{
const parent = document.querySelector('#jumpgate');
if(!parent || parent.querySelector('.ogl_limiterLabel')) return;
document.querySelectorAll('#jumpgate .ship_input_row').forEach(line =>
{
if(line.previousElementSibling.classList.contains('tdInactive')) return;
const input = line.querySelector('input');
const shipID = input.getAttribute('id').replace('ship_', '');
this.initialRel[shipID] = parseInt(input.getAttribute('rel'));
});
const limiterField = Util.addDom('fieldset', { parent:document.querySelector('#jumpgateForm .ship_selection_table') });
Util.addDom('legend', { parent:limiterField, child:'Settings' });
const limitShipLabel = Util.addDom('label', { class:'ogl_limiterLabel', parent:limiterField, child:'Ships' });
const limitShipCheckbox = Util.addDom('input', { type:'checkbox', parent:limitShipLabel, onclick:() =>
{
this.ogl.db.fleetLimiter.jumpgateActive = !this.ogl.db.fleetLimiter.jumpgateActive;
this.updateLimiter();
}});
const keepLabel = Util.addDom('div', { class:'ogl_limiterGroup', parent:limiterField, child:'Force (jumpgate)' });
[202, 203, 219, 200].forEach(shipID =>
{
const item = Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, parent:keepLabel, onclick:() =>
{
keepLabel.querySelector('.ogl_active')?.classList.remove('ogl_active');
item.classList.add('ogl_active');
this.ogl.db.keepEnoughCapacityShipJumpgate = shipID;
this.updateLimiter();
}});
if(this.ogl.db.keepEnoughCapacityShipJumpgate == shipID) item.classList.add('ogl_active');
});
if(this.ogl.db.fleetLimiter.jumpgateActive) limitShipCheckbox.checked = true;
this.updateLimiter();
}
updateLimiter()
{
if(!document.querySelector('#jumpgate') || document.querySelector('#jumpgateNotReady')) return;
const sendAllJson = {};
document.querySelectorAll('#jumpgate .ship_input_row').forEach(line =>
{
if(line.previousElementSibling.classList.contains('tdInactive')) return;
const input = line.querySelector('input');
const shipID = input.getAttribute('id').replace('ship_', '');
let forced = 0;
if(this.ogl.db.keepEnoughCapacityShipJumpgate == shipID)
{
forced = this.ogl._fleet.shipsForResources(shipID);
}
const keeped = Math.max(forced, (this.ogl.db.fleetLimiter.jumpgateActive ? (this.ogl.db.fleetLimiter.jumpgateData[shipID] || 0) : 0));
const amount = Math.max(0, this.initialRel[shipID] - keeped);
input.setAttribute('rel', amount);
if(input.value > amount) input.value = amount;
line.previousElementSibling.querySelector('.quantity').setAttribute('onclick', `toggleMaxShips('#jumpgateForm', ${shipID}, ${amount})`);
line.previousElementSibling.querySelector('a').setAttribute('onclick', `toggleMaxShips('#jumpgateForm', ${shipID}, ${amount})`);
let text = line.querySelector('.ogl_keepRecap') || Util.addDom('div', { parent:line, class:'ogl_keepRecap' });
text.innerText = `-${keeped}`;
text.addEventListener('click', () => { Util.runAsync(() => this.ogl._ui.openFleetProfile()).then(e => this.ogl._popup.open(e)); });
sendAllJson[shipID] = amount;
});
document.querySelector('#jumpgate #sendall').setAttribute('onclick', `setMaxIntInput("#jumpgateForm", ${JSON.stringify(sendAllJson)})`);
}
checkPhalanx()
{
const parent = document.querySelector('.ui-dialog .phalanx').parentElement.querySelector('.ui-dialog-titlebar .ui-dialog-title');
this.lastPhalanxRefresh = Date.now();
if(parent.querySelector('.ogl_phalanxLastRefresh')) return;
const refresh = Util.addDom('span', { class:'ogl_phalanxLastRefresh', parent:parent, child:'<b>0s</b>' });
setInterval(() =>
{
refresh.innerText = `${Math.floor(( Date.now() - this.lastPhalanxRefresh) / 1000)}s`;
}, 500);
/*
const clock = document.querySelector('.OGameClock').cloneNode(true);
clock.className='';
container.appendChild(clock);
const refresh = Util.addDom('span', { parent:container, child:' - <b>0s</b>' });
setInterval(() =>
{
const currentTime = parseInt(document.querySelector('.OGameClock').getAttribute('data-time-server'));
const refreshTime = parseInt(clock.getAttribute('data-time-server'));
refresh.innerHTML = ` - <b>${Math.round((currentTime - refreshTime) / 1000)}s</b>`;
}, 1000);*/
}
saveTimer()
{
const calcTimer = level =>
{
return (0.25 * Math.pow(level, 2) - 7.57 * level + 67.34) / this.ogl.server.warFleetSpeed * 60000;
}
jumpgateDone = a =>
{
var a = $.parseJSON(a);
if(a.status)
{
planet = a.targetMoon;
$(".overlayDiv").dialog("destroy");
const originID = this.ogl.currentPlanet.obj.id;
const originLevel = this.ogl.currentPlanet.dom._ogl.jumpgateLevel;
const destinationLevel = this.ogl._dom.planet[jumpGateTargetId].getAttribute('data-jumpgatelevel');
const now = serverTime.getTime();
this.ogl.db.myPlanets[originID].jumpgateTimer = now + calcTimer(originLevel);
this.ogl.db.myPlanets[jumpGateTargetId].jumpgateTimer = now + calcTimer(destinationLevel);
}
errorBoxAsArray(a.errorbox);
if(typeof(a.newToken) != "undefined") setNewTokenData(a.newToken);
}
}
displayTimer()
{
document.querySelectorAll('.moonlink').forEach(moon =>
{
const targetDom = moon.parentNode.querySelector(`.ogl_sideIconInfo`) || Util.addDom('div', { class:'ogl_sideIconInfo tooltip', 'title':'Jumpgate not ready', parent:moon.parentNode });
const moonID = moon.getAttribute('href').match(/cp=(\d+)/)[1];
if(this.ogl.db.myPlanets[moonID]?.jumpgateTimer > serverTime.getTime())
{
const updateTimer = () => new Date(this.ogl.db.myPlanets[moonID].jumpgateTimer - (serverTime.getTime() + 3600000)).toLocaleTimeString([], { minute:'2-digit', second:'2-digit' });
const div = Util.addDom('div', { class:'ogl_jumpgateTimer', parent:targetDom, child:updateTimer() });
let interval = setInterval(() =>
{
if(this.ogl.db.myPlanets[moonID].jumpgateTimer <= serverTime.getTime())
{
clearInterval(interval);
div.remove();
}
else div.innerText = updateTimer();
}, 1000);
}
});
}
}
class AccountManager extends Manager
{
load()
{
this.buildingList = [1, 2, 3, 4, 12, 14, 15, 21, 22, 23, 24, 31, 33, 34, 36, 44];
this.buildingListMoon = [14, 21, 41, 42, 43];
this.defenseList = [401, 402, 403, 404, 405, 406, 407, 408, 502];
this.shipsList = [...this.ogl.shipsList, 217];
this.fleetEconomyHalfValue = [202, 203, 208, 210, 209, 217];
this.calcCumul();
this.calcScore();
}
openSummary(fetchData)
{
if(fetchData)
{
this.ogl._popup.open(Util.addDom('div', { child:'<h2>Fetching account data, please wait</h2><div class="ogl_blocCenter ogl_loading"></div>' }));
this.ogl._fetch.fetchMainData(() => this.openSummary(), true);
}
else
{
if(this.ogl._popup.isActive())
{
this.calcCumul();
this.openMethod(this.ogl.db.lastAccountTab, this.ogl.db.lastAccountTab);
}
}
}
openEmpire()
{
const content = Util.addDom('div', { class:'ogl_accountContainer ogl_accountMain', child:
`
<div class="ogl_accountRank">
<i class="material-icons">crown</i>
<div class="ogl_accountScore">${Util.formatToUnits(this.score.global)} pts</div>
<div class="ogl_accountRanking">#${Util.formatNumber(this.ranking.global)}</div>
<div class="ogl_accountGraph"></div>
</div>
<div class="ogl_accountRank ogl_accountEconomy">
<i class="material-icons">diamond</i>
<div class="ogl_accountScore">${Util.formatToUnits(this.score.economy)} pts</div>
<div class="ogl_accountRanking">#${Util.formatNumber(this.ranking.economy)}</div>
<div class="ogl_accountProduction">
<div class="ogl_icon ogl_metal">${Util.formatNumber(this.cumul.planet.mineMetal / this.cumul.planet.count, 1)}</div>
<div class="ogl_icon ogl_crystal">${Util.formatNumber(this.cumul.planet.mineCrystal / this.cumul.planet.count, 1)}</div>
<div class="ogl_icon ogl_deut">${Util.formatNumber(this.cumul.planet.mineDeut / this.cumul.planet.count, 1)}</div>
<div class="ogl_icon ogl_metal ogl_plus">+${Util.formatToUnits(Math.round((this.cumul.planet.prodMetal || 0) * 3600 * 24))}</div>
<div class="ogl_icon ogl_crystal ogl_plus">+${Util.formatToUnits(Math.round((this.cumul.planet.prodCrystal || 0) * 3600 * 24))}</div>
<div class="ogl_icon ogl_deut ogl_plus">+${Util.formatToUnits(Math.round((this.cumul.planet.prodDeut || 0) * 3600 * 24))}</div>
<div class="ogl_icon ogl_113">${this.ogl.currentPlanet.obj[113]}</div>
<div class="ogl_icon ogl_122">${this.ogl.currentPlanet.obj[122]}</div>
<div class="ogl_icon ogl_124">${this.ogl.currentPlanet.obj[124]}</div>
</div>
</div>
<div class="ogl_accountRank ogl_accountFleet">
<i class="material-icons">rocket_launch</i>
<div class="ogl_accountScore">${Util.formatToUnits(this.score.fleet)} pts</div>
<div class="ogl_accountRanking">#${Util.formatToUnits(this.ranking.fleet)}</div>
<div class="ogl_accountProduction">
<div class="ogl_icon ogl_109">${this.ogl.currentPlanet.obj[109]}</div>
<div class="ogl_icon ogl_110">${this.ogl.currentPlanet.obj[110]}</div>
<div class="ogl_icon ogl_111">${this.ogl.currentPlanet.obj[111]}</div>
<div class="ogl_icon ogl_115">${this.ogl.currentPlanet.obj[115]}</div>
<div class="ogl_icon ogl_117">${this.ogl.currentPlanet.obj[117]}</div>
<div class="ogl_icon ogl_118">${this.ogl.currentPlanet.obj[118]}</div>
</div>
</div>
<div class="ogl_accountRank ogl_accountLifeform">
<i class="material-icons">genetics</i>
<div class="ogl_accountScore">${Util.formatToUnits(this.score.lifeform)} pts</div>
<div class="ogl_accountRanking">#${Util.formatNumber(this.ranking.lifeform)}</div>
<div class="ogl_accountProduction">
<div class="ogl_icon ogl_lifeform1">${(this.ogl.db.lfBonuses?.lifeform1?.bonus || 0) * 10}</div>
<div class="ogl_icon ogl_lifeform2">${(this.ogl.db.lfBonuses?.lifeform2?.bonus || 0) * 10}</div>
<div class="ogl_icon ogl_lifeform3">${(this.ogl.db.lfBonuses?.lifeform3?.bonus || 0) * 10}</div>
<div class="ogl_icon ogl_lifeform4">${(this.ogl.db.lfBonuses?.lifeform4?.bonus || 0) * 10}</div>
</div>
</div>
`});
const icons =
{
'global':'crown',
'economy':'diamond',
'research':'science',
'fleet':'rocket_launch',
'defense':'security',
'lifeform':'genetics',
}
Object.entries(this.scorePercent).forEach(entry =>
{
Util.addDom('div', { class:'ogl_accountBar', parent:content.querySelector('.ogl_accountGraph'), child:`<label data-value="(${entry[1]}%)">${icons[entry[0]]}</label>`, style:`height:${Math.ceil(parseFloat(entry[1] || 0) / 2)}px` });
});
const container = Util.addDom('div', { class:'ogl_accountSummary' });
container.appendChild(this.addTabs('empire'));
container.appendChild(content);
this.ogl._popup.open(container);
}
openProduction()
{
const container = Util.addDom('div', { class:'ogl_accountSummary' });
container.appendChild(this.addTabs('production'));
const grid = Util.addDom('div', { class:'ogl_accountContainer ogl_accountEmpire ogl_grid', parent:container });
Util.addDom('div', { class:'ogl_line', parent:grid, child:
`
<div>Coords</div>
<div>P</div>
<div>M</div>
<div>Name</div>
<div>Fields</div>
<div>T°c</div>
<div>LF</div>
<div class="ogl_icon ogl_metal"></div>
<div class="ogl_icon ogl_crystal"></div>
<div class="ogl_icon ogl_deut"></div>
`});
document.querySelectorAll('.smallplanet .planetlink').forEach(item =>
{
const planet = this.ogl.db.myPlanets[item._ogl.id];
if(!planet) return;
const metalUpgrade = Object.values(planet.upgrades?.baseBuilding || {}).find(e => e.id == 1);
const crystalUpgrade = Object.values(planet.upgrades?.baseBuilding || {}).find(e => e.id == 2);
const deutUpgrade = Object.values(planet.upgrades?.baseBuilding || {}).find(e => e.id == 3);
const line = Util.addDom('div', { class:'ogl_line', parent:grid, child:
`
<div data-galaxy="${planet.coords}">${planet.coords}</div>
<a href="${item.getAttribute('href')}"><img src="${item.querySelector('.planetPic')?.getAttribute('src')}"></a>
${
item._ogl.moonLink
? `<a href="${item._ogl.moonLink.getAttribute('href')}"><img src="${item._ogl.moonLink.querySelector('.moonlink img')?.getAttribute('src')}"></a>`
: '<div>-</div>'
}
<div>${item._ogl.name}</div>
<div>${planet.fieldUsed}/${planet.fieldMax} (<span>${planet.fieldMax-planet.fieldUsed}</span>)</div>
<div class="ogl_temperature">${planet.temperature+40}°c</div>
<div class="ogl_icon ogl_lifeform${planet.lifeform || 0}"></div>
<div class="ogl_metal">
<strong>${planet[1]}</strong>
<div class="ogl_upgrade">${metalUpgrade ? `(${metalUpgrade.lvl})` : ``}</div>
<small>+${Util.formatToUnits(Math.round((planet.prodMetal || 0) * 3600 * 24))}</small>
</div>
<div class="ogl_crystal">
<strong>${planet[2]}</strong>
<div class="ogl_upgrade">${crystalUpgrade ? `(${crystalUpgrade.lvl})` : ``}</div>
<small>+${Util.formatToUnits(Math.round((planet.prodCrystal || 0) * 3600 * 24))}</small>
</div>
<div class="ogl_deut">
<strong>${planet[3]}</strong>
<div class="ogl_upgrade">${deutUpgrade ? `(${deutUpgrade.lvl})` : ``}</div>
<small>+${Util.formatToUnits(Math.round((planet.prodDeut || 0) * 3600 * 24))}</small>
</div>
`});
const temperature = line.querySelector('.ogl_temperature');
if(planet.temperature >= 110) temperature.style.color = "#af644d"; // too hot
else if(planet.temperature >= 10) temperature.style.color = "#af9e4d"; // hot
else if(planet.temperature >= -40) temperature.style.color = "#4daf67"; // normal
else if(planet.temperature >= -140) temperature.style.color = "#4dafa6"; // cold
else temperature.style.color = "#4d79af"; // too cold
});
Util.addDom('div', { class:'ogl_line', parent:grid, child:
`
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_invisible"></div>
<div class="ogl_metal">
<strong>${Util.formatNumber(this.cumul.planet.mineMetal / this.cumul.planet.count, 1)}</strong>
<small>+${Util.formatToUnits(Math.round((this.cumul.planet.prodMetal || 0) * 3600 * 24))}</small>
</div>
<div class="ogl_crystal">
<strong>${Util.formatNumber(this.cumul.planet.mineCrystal / this.cumul.planet.count, 1)}</strong>
<small>+${Util.formatToUnits(Math.round((this.cumul.planet.prodCrystal || 0) * 3600 * 24))}</small>
</div>
<div class="ogl_deut">
<strong>${Util.formatNumber(this.cumul.planet.mineDeut / this.cumul.planet.count, 1)}</strong>
<small>+${Util.formatToUnits(Math.round((this.cumul.planet.prodDeut || 0) * 3600 * 24))}</small>
</div>
`});
this.ogl._popup.open(container);
}
openPlanets(type, tech)
{
type = type || 'planets'; // planets / moons
tech = tech || 'buildings'; // buildings / ships / defenses / lifeforms
let cumulFleetPercent = 0;
const list = type == 'planets' ? this.buildingList : this.buildingListMoon;
const container = Util.addDom('div', { class:'ogl_accountSummary' });
container.appendChild(this.addTabs(type, tech));
const grid = Util.addDom('div', { class:'ogl_accountContainer ogl_accountShips ogl_grid', parent:container });
const header = Util.addDom('div', { class:'ogl_line', parent:grid, child:`<div>Coords</div>` });
// headers
if(tech =='ships')
{
['metal', 'crystal', 'deut', ...this.shipsList].forEach(itemID =>
{
Util.addDom('div', { class:`ogl_icon ogl_${itemID} tooltip`, parent:header, title:this.ogl._lang.find(itemID) });
});
Util.addDom('div', { parent:header, child:'%' });
}
else if(tech == 'defenses')
{
this.defenseList.forEach(itemID =>
{
Util.addDom('div', { class:`ogl_icon ogl_${itemID} tooltip`, parent:header, title:this.ogl._lang.find(itemID) });
});
}
else if(tech == 'buildings')
{
list.forEach(itemID =>
{
Util.addDom('div', { class:`ogl_icon ogl_${itemID} tooltip`, parent:header, title:this.ogl._lang.find(itemID) });
});
}
const selector = type == 'planets' ? '.smallplanet .planetlink' : '.smallplanet .moonlink';
document.querySelectorAll(selector).forEach(item =>
{
const planet = this.ogl.db.myPlanets[item._ogl.id];
if(!planet) return;
const line = Util.addDom('div', { class:'ogl_line', parent:grid, child:`<div data-galaxy="${planet.coords}">${planet.coords}</div>` });
// lines
if(tech =='ships')
{
let fleetValue = 0;
['metal', 'crystal', 'deut', ...this.shipsList].forEach(itemID =>
{
const entry = Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':planet[itemID] || 0, parent:line, child:Util.formatToUnits(planet[itemID], 0) });
const shipValueScaling = this.fleetEconomyHalfValue.indexOf(itemID) > -1 ? .5 : 1;
if(!isNaN(itemID))
{
const shipValue = Object.values(Datafinder.getTech(itemID)).reduce((sum, value) => sum + value, 0) / 1000 * planet[itemID] * shipValueScaling;
entry.dataset.value = shipValue;
fleetValue += shipValue;
}
});
const fleetPercent = fleetValue / this.score.fleet * 100;
const percent = Util.addDom('div', { parent:line, child:`<div>${Util.formatNumber(Math.min(100, fleetPercent), 1)}%</div>` });
if(fleetPercent >= 30) percent.style.color = "#af644d"; // too hot
else if(fleetPercent >= 20) percent.style.color = "#af9e4d"; // hot
else if(fleetPercent >= 10) percent.style.color = "#4daf67"; // normal
else if(fleetPercent >= 5) percent.style.color = "#4dafa6"; // cold
else percent.style.color = "#4d79af"; // too cold
cumulFleetPercent += fleetPercent;
}
else if(tech == 'defenses')
{
this.defenseList.forEach(itemID =>
{
Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':planet[itemID] || 0, parent:line, child:Util.formatToUnits(planet[itemID], 0) });
});
}
else if(tech == 'buildings')
{
list.forEach(itemID =>
{
Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':planet[itemID] || 0, parent:line, child:Util.formatToUnits(planet[itemID], 0) });
});
}
});
const footer = Util.addDom('div', { class:'ogl_line', parent:grid, child:`<div>Total</div>` });
// footer
if(tech =='ships')
{
['metal', 'crystal', 'deut', ...this.shipsList].forEach(itemID =>
{
const amount = this.cumul[type.replace('s', '')]?.[itemID] || 0;
Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':amount, parent:footer, child:Util.formatToUnits(amount, 0) });
});
Util.addDom('div', { parent:footer, child:`${Util.formatToUnits(cumulFleetPercent, 1)}%` });
}
else if(tech =='defenses')
{
this.defenseList.forEach(itemID =>
{
const amount = this.cumul[type.replace('s', '')]?.[itemID] || 0;
Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':amount, parent:footer, child:Util.formatToUnits(amount, 0) });
});
}
else if(tech =='buildings')
{
list.forEach(itemID =>
{
const amount = this.cumul[type.replace('s', '')]?.[itemID] || 0;
Util.addDom('div', { class:`ogl_${itemID}`, 'data-amount':amount, parent:footer, child:Util.formatToUnits(amount, 0) });
});
}
this.ogl._popup.open(container);
}
openMoons(type, tech)
{
this.openPlanets(type, tech);
}
calcCumul()
{
this.cumul = { planet:{}, moon:{} };
Object.values(this.ogl.db.myPlanets).forEach(planet =>
{
if(!planet.type || (planet.type != 'planet' && planet.type != 'moon')) return;
this.cumul[planet.type].metal = (this.cumul[planet.type].metal || 0) + (planet.metal || 0);
this.cumul[planet.type].crystal = (this.cumul[planet.type].crystal || 0) + (planet.crystal || 0);
this.cumul[planet.type].deut = (this.cumul[planet.type].deut || 0) + (planet.deut || 0);
this.cumul[planet.type].mineMetal = (this.cumul[planet.type].mineMetal || 0) + (planet[1] || 0);
this.cumul[planet.type].mineCrystal = (this.cumul[planet.type].mineCrystal || 0) + (planet[2] || 0);
this.cumul[planet.type].mineDeut = (this.cumul[planet.type].mineDeut || 0) + (planet[3] || 0);
this.cumul[planet.type].prodMetal = (this.cumul[planet.type].prodMetal || 0) + planet.prodMetal;
this.cumul[planet.type].prodCrystal = (this.cumul[planet.type].prodCrystal || 0) + planet.prodCrystal;
this.cumul[planet.type].prodDeut = (this.cumul[planet.type].prodDeut || 0) + planet.prodDeut;
this.cumul[planet.type].count = (this.cumul[planet.type].count || 0) + 1;
this.cumul[planet.type]['lifeform'+(planet.lifeform || 0)] = (this.cumul[planet.type]['lifeform'+(planet.lifeform || 0)] || 0) + 1;
[...this.shipsList].forEach(techID => this.cumul[planet.type][techID] = (this.cumul[planet.type][techID] || 0) + planet[techID]);
this.defenseList.forEach(techID => this.cumul[planet.type][techID] = (this.cumul[planet.type][techID] || 0) + planet[techID]);
this.buildingList.forEach(techID => this.cumul[planet.type][techID] = (this.cumul[planet.type][techID] || 0) + planet[techID]);
this.buildingListMoon.forEach(techID => this.cumul[planet.type][techID] = (this.cumul[planet.type][techID] || 0) + planet[techID]);
});
}
calcScore()
{
this.score = {};
this.scorePercent = {};
this.ranking = {};
const player = this.ogl.db.udb[this.ogl.account.id];
if(!player) return;
this.score.global = player.score.global;
this.score.economy = player.score.economy;
this.score.research = player.score.research;
this.score.lifeform = player.score.lifeform;
this.score.fleet = Util.getPlayerScoreFD(player.score, 'fleet');
this.score.defense = Util.getPlayerScoreFD(player.score, 'defense');
this.ranking.global = player.score.globalRanking;
this.ranking.economy = player.score.economyRanking;
this.ranking.research = player.score.researchRanking;
this.ranking.lifeform = player.score.lifeformRanking;
this.ranking.fleet = player.score.militaryRanking;
this.ranking.defense = player.score.militaryRanking;
this.scorePercent.global = 100;
this.scorePercent.economy = Util.formatNumber(this.score.economy / this.score.global * 100, 2);
this.scorePercent.research = Util.formatNumber(this.score.research / this.score.global * 100, 2);
this.scorePercent.lifeform = Util.formatNumber(this.score.lifeform / this.score.global * 100, 2);
this.scorePercent.fleet = Util.formatNumber(this.score.fleet / this.score.global * 100, 2);
this.scorePercent.defense = Util.formatNumber(this.score.defense / this.score.global * 100, 2);
}
addTabs(activeType, activeTech)
{
const items =
[
{ title:'empire', icon:'account_balance', type:'empire' },
{ title:'production', icon:'factory', type:'production' },
//{ title:'research', icon:'science', type:'research' },
{
title:'planets', icon:'planet', type:'planets',
subItems: [
{ title:'buildings', icon:'diamond', tech:'buildings' },
{ title:'ships', icon:'rocket_launch', tech:'ships' },
{ title:'defenses', icon:'security', tech:'defenses' },
//{ title:'lifeforms', icon:'genetics', tech:'lifeforms' },
]
},
{
title:'moons', icon:'bedtime', type:'moons',
subItems: [
{ title:'buildings', icon:'diamond', tech:'buildings' },
{ title:'ships', icon:'rocket_launch', tech:'ships' },
{ title:'defenses', icon:'security', tech:'defenses' },
//{ title:'lifeforms', icon:'genetics', tech:'lifeforms' },
]
},
];
const container = Util.addDom('div');
const tabs = Util.addDom('div', { class:'ogl_tabs', parent:container });
const subtabs = Util.addDom('div', { class:'ogl_tabs', parent:container });
items.forEach(item =>
{
const btn = Util.addDom('div', { class:'ogl_tab', child:`<i class="material-icons">${item.icon}</i><span>${item.title}</span>`, parent:tabs, onclick:e =>
{
this.openMethod(item);
}});
if(activeType == item.type)
{
btn.classList.add('ogl_active');
if(!item.subItems) return;
item.subItems.forEach(subItem =>
{
const subbtn = Util.addDom('div', { class:'ogl_tab', child:`<i class="material-icons">${subItem.icon}</i><span>${subItem.title}</span>`, parent:subtabs, onclick:e =>
{
this.openMethod(item, subItem);
}});
if(activeTech == subItem.tech)
{
subbtn.classList.add('ogl_active');
}
});
}
//if(activeType == item.type && activeTech == item.tech) btn.classList.add('ogl_active');
});
return container;
}
openMethod(item, subItem)
{
if(!item || !item.type)
{
this.ogl.db.lastAccountTab = { type:'empire' };
this.openEmpire();
}
else
{
const methodName = `open${item.type.charAt(0).toUpperCase() + item.type.slice(1)}`;
if(typeof this[methodName] === 'function')
{
this.ogl.db.lastAccountTab = { type:item.type, tech:subItem?.tech };
this[methodName](item.type, subItem?.tech);
}
else
{
this.ogl.db.lastAccountTab = { type:'empire' };
this.openEmpire();
}
}
}
}
class TooltipManager extends Manager
{
load()
{
this.openTimeout;
this.lastSender;
this.lastActiveSender;
this.shouldWait = false;
if(unsafeWindow['tippy'])
{
Util.overWrite('initTooltips', unsafeWindow, null, () =>
{
this.initTooltipList(document.querySelectorAll(getTooltipSelector()));
});
}
this.tooltip = Util.addDom('div',
{
class:'ogl_tooltip',
parent:document.body
});
// fix resources tooltips
if(!document.querySelector('#metal_box')?.getAttribute('title')) getAjaxResourcebox();
if(unsafeWindow['tippy']) initTooltips();
else this.init();
}
initTooltipList(nodeList)
{
this.lastReference = false;
nodeList.forEach(element =>
{
if(!element._tippy?.oglTooltipReady)
{
if(element.title && !element.getAttribute('data-tooltip-title')) element.setAttribute('data-tooltip-title', element.title);
element.removeAttribute('title');
if(!element._tippy)
{
const getDirection = () =>
{
return element.classList.contains('tooltipBottom') ? 'bottom' :
element.classList.contains('tooltipRight') ? 'right' :
element.classList.contains('tooltipLeft') ? 'left' : 'top';
}
tippy(element,
{
content:element.getAttribute('data-tooltip-title'),
allowHTML:true,
appendTo:document.body,
zIndex:1000001,
placement:getDirection(),
interactive:element.getAttribute('data-tooltip-interactive') || false,
maxWidth:400
});
}
if(element._tippy)
{
element._tippy.setProps(
{
animation:'pop',
delay:[element.classList.contains('tooltipClick') ? 0 : 400 , null],
duration: [100, 10],
interactive:(element.classList.contains('tooltipClose') || element.classList.contains('tooltipRel')) ? true : false,
interactiveBorder:15,
interactiveDebounce:75,
trigger:element.classList.contains('tooltipClick') ? 'click focus' : 'mouseenter focus',
onShow:instance =>
{
if(this.lastReference !== instance.reference) return false;
tippy.hideAll();
let content = instance.props.content || element.getAttribute('data-tooltip-title');
if(element.classList.contains('planetlink')) content = this.updatePlanetMenuTooltip(instance, 'planet') ?? content;
else if(element.classList.contains('moonlink')) content = this.updatePlanetMenuTooltip(instance, 'moon') ?? content;
else if(typeof content == 'string' && content.indexOf('class="fleetinfo') >= 0) content = this.updateFleetTooltip(instance);
if(!content || content === false || content === '') return false;
else if(content) instance.setContent(content);
if(element.classList.contains('tooltipUpdate'))
{
element.dispatchEvent(this.ogl.tooltipEvent);
}
instance.popper.classList.add('ogl_noTouch');
},
onTrigger:instance =>
{
//tippy.hideAll();
this.lastReference = instance.reference;
element.removeAttribute('title');
},
onShown:instance =>
{
instance.popper.classList.remove('ogl_noTouch');
this.ogl._fleet.checkSendShips();
},
onHide:instance =>
{
if(this.lastReference === instance.reference) this.lastReference = false;
}
});
element._tippy.oglTooltipReady = true;
element.classList.add('ogl_ready');
}
}
});
}
updatePlanetMenuTooltip(instance, refType)
{
if(this.ogl.db.options.disablePlanetTooltips) return false;
if(instance.oglContentInjected) return;
if(refType == 'planet')
{
instance.setProps({ placement:'left' });
const planetID = instance.reference.parentNode.getAttribute('id').replace('planet-', '');
const name = instance.reference.querySelector('.planet-name').innerText;
const data = this.ogl.db.myPlanets[planetID];
const div = Util.addDom('div', { class:'ogl_planetTooltip' });
const links = new DOMParser().parseFromString(instance.props.content, 'text/html').querySelectorAll('a');
if(!data) return;
div.innerHTML =
`
<div>
<h3>${name}<br><span data-galaxy="${data.coords}">[${data.coords}]</span></h3>
<div>
${
data?.lifeform
? `<div class="ogl_icon ogl_lifeform${data.lifeform}"></div>`
: ``
}
<div>${instance.reference.querySelector('.planetPic').outerHTML}</div>
</div>
<div class="ogl_planetTooltipData">
<div class="ogl_textCenter"><i class="material-icons">flex_wrap</i>${data.fieldUsed}/${data.fieldMax}</div>
<div class="ogl_textCenter"><i class="material-icons">device_thermostat</i>${data.temperature + 40}°c</div>
</div>
<div class="ogl_mineRecap"><span class='ogl_metal'>${data[1]}</span> <span class='ogl_crystal'>${data[2]}</span> <span class='ogl_deut'>${data[3]}</span></div>
</div>
`;
const linkDiv = Util.addDom('div', { class:'ogl_linkDiv', parent:div });
links.forEach(e => linkDiv.appendChild(e));
if(this.ogl._topbar?.PlanetBuildingtooltip[planetID])
{
div.appendChild(this.ogl._topbar?.PlanetBuildingtooltip[planetID]);
}
instance.oglContentInjected = true;
return div.outerHTML;
}
else if(refType == 'moon')
{
instance.setProps({ placement:'right' });
const urlParams = new URLSearchParams(instance.reference.getAttribute('href'));
const planetID = urlParams.get('cp').split('#')[0];
const name = instance.reference.querySelector('.icon-moon').getAttribute('alt');
const data = this.ogl.db.myPlanets[planetID];
const div = Util.addDom('div', { class:'ogl_planetTooltip' });
const links = new DOMParser().parseFromString(instance.props.content, 'text/html').querySelectorAll('a');
const jumpgate = instance.reference.dataset.jumpgatelevel || '0';
if(!data) return;
div.innerHTML =
`
<div>
<h3>${name}<br><span data-galaxy="${data.coords}">[${data.coords}]</span></h3>
<div>
${
data?.lifeform
? `<div class="ogl_icon ogl_lifeform${data.lifeform}"></div>`
: ``
}
<div>${instance.reference.querySelector('.icon-moon').outerHTML}</div>
</div>
<div class="ogl_planetTooltipData">
<div class="ogl_textCenter"><i class="material-icons">flex_wrap</i>${data.fieldUsed}/${data.fieldMax}</div>
<div class="ogl_textCenter"><i class="material-icons">door_back</i>${jumpgate}</div>
</div>
</div>
`;
const linkDiv = Util.addDom('div', { class:'ogl_linkDiv', parent:div });
links.forEach(e => linkDiv.appendChild(e));
if(this.ogl._topbar?.PlanetBuildingtooltip[planetID])
{
div.appendChild(this.ogl._topbar?.PlanetBuildingtooltip[planetID]);
}
instance.oglContentInjected = true;
return div.outerHTML;
}
}
updateFleetTooltip(instance)
{
const sender = instance.reference;
const xml = new DOMParser().parseFromString(instance.props.content, 'text/html');
const div = Util.addDom('div', { class:'ogl_fleetDetail' });
let origin = (sender.closest('.eventFleet')?.querySelector('.coordsOrigin') || sender.closest('.fleetDetails')?.querySelector('.originData a'))?.innerText.slice(1, -1);
origin = origin || { galaxy:0, system:0, position:0 };
let originType = (sender.closest('.eventFleet')?.querySelector('.originFleet figure.moon') || sender.closest('.fleetDetails')?.querySelector('.originPlanet figure.moon')) ? 'moon' : 'planet';
let destination = (sender.closest('.eventFleet')?.querySelector('.destCoords') || sender.closest('.fleetDetails')?.querySelector('.destinationData a'))?.innerText.slice(1, -1);
destination = destination || { galaxy:0, system:0, position:0 };
let destinationType = (sender.closest('.eventFleet')?.querySelector('.destFleet figure.moon') || sender.closest('.fleetDetails')?.querySelector('.destinationPlanet figure.moon')) ? 'moon' : 'planet';
const meAsAttacker = Array.from(document.querySelectorAll('.planet-koords')).find(e => e.innerText == origin) ? true : false;
const meAsDefender = Array.from(document.querySelectorAll('.planet-koords')).find(e => e.innerText == destination) ? true : false;
let rawText = '';
let trashsimData =
{
ships:{},
meAsAttacker:meAsAttacker,
meAsDefender:meAsDefender,
origin:{ coords:origin, type:originType },
destination:{ coords:destination, type:destinationType }
};
xml.querySelectorAll('tr').forEach(line =>
{
const name = line.querySelector('td')?.innerText.replace(':', '');
const key = Object.entries(this.ogl.db.serverData).find(entry => entry[1] === name)?.[0];
const value = line.querySelector('.value')?.innerText.replace(/\.|,| /g, '');
if(key && value)
{
if(key == 'metal') Util.addDom('hr', { parent:div });
const val = key == 'metal' || key == 'crystal' || key == 'deut' || key == 'food' ? Util.formatNumber(parseInt(value)) : Util.formatToUnits(value);
Util.addDom('div', { parent:div, class:`ogl_icon ogl_${key}`, child:val });
trashsimData.ships[key] = { count:value };
rawText += `${name}: ${Util.formatNumber(parseInt(value))}\n`;
}
});
if(rawText.length > 0 && !xml.querySelector('.ogl_custom'))
{
const container = Util.addDom('span', { parent:div, class:'ogl_fullgrid' });
Util.addDom('hr', { parent:container });
const btn = Util.addDom('button',
{
class:'ogl_button',
parent:container,
child:'<span class="material-icons">file_copy</span><span>Copy</span>',
onclick:() =>
{
navigator.clipboard.writeText(rawText);
btn.classList.remove('material-icons');
btn.innerText = 'Copied!';
}
});
if(origin)
{
Util.addDom('div',
{
class:'ogl_button',
parent:container,
child:'<span class="material-icons">play_arrow</span><span>Simulate</span>',
onclick:() =>
{
window.open(Util.genTrashsimLink(this.ogl, false, trashsimData), '_blank');
}
});
}
}
if(rawText.length > 0) return div;
else return false;
}
}
class NotificationManager extends Manager
{
load()
{
this.data = {};
this.blocks = [];
this.interval;
this.hideTimer = 5000;
this.step = 200;
this.currentValue = this.hideTimer;
this.start = 0;
this.timeLeft = this.hideTimer;
this.elapsedInterval;
this.notification = Util.addDom('div', { class:'ogl_notification', parent:document.body,
onmouseenter:() =>
{
clearInterval(this.interval);
},
onmouseleave:() =>
{
this.interval = setInterval(() => this.updateClock(), this.step);
},
onclick:() =>
{
this.close();
}});
this.clock = Util.addDom('progress', { parent:this.notification, min:0, max:this.hideTimer, value:this.currentValue });
this.content = Util.addDom('div', { parent:this.notification });
setInterval(() =>
{
Object.values(this.ogl.db.browserNotificationList).forEach(notif =>
{
if(notif.arrivalTime <= serverTime.getTime())
{
this.triggerBrowserNotification(notif);
}
});
}, 10000);
}
open()
{
this.content.innerText = '';
if(this.ogl._message.events?.mission) this.ogl._message.events.mission = 0;
const data = {};
let blockCount = 0;
this.blocks.forEach(block =>
{
let icon = Util.addDom('i');
if(block.success > 0) icon = Util.addDom('i', { class:'material-icons ogl_ok', child:'done' });
else if(block.success < 0) icon = Util.addDom('i', { class:'material-icons ogl_danger', child:'alert' });
if(block.data)
{
Object.entries(block.data).forEach(entry =>
{
data[entry[0]] = (data[entry[0]] || 0) + (entry[1] || 0);
});
}
if(block.message)
{
const timeObj = this.ogl._time.getObj(block.time);
const time = this.ogl._time.timeToHMS(this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server);
const line = Util.addDom('div', { class:'ogl_notificationLine', child:`${icon.outerHTML}<b class="ogl_notificationTimer">[${time}]</b>` + block.message, prepend:this.content });
if(block.success < 0) line.classList.add('ogl_danger');
}
else
{
blockCount++;
}
});
if(blockCount > 0)
{
const timeObj = this.ogl._time.getObj();
const time = this.ogl._time.timeToHMS(this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server);
Util.addDom('div', { class:'ogl_notificationLine', child:`<b class="ogl_notificationTimer">[${time}]</b>` + `${blockCount} mission(s) added`, prepend:this.content });
}
if(Object.keys(data).length > 0)
{
let hasResources = false;
let hasShips = false;
let hasLifeforms = false;
let hasExpeditions = false;
const grid = Util.addDom('div', { class:'ogl_grid', prepend:this.content });
['metal', 'crystal', 'deut', 'dm'].forEach(type =>
{
if(data[type])
{
Util.addDom('div', { class:`ogl_icon ogl_${type}`, child:Util.formatToUnits(data[type]), parent:grid });
hasResources = true;
}
});
if(hasResources) Util.addDom('hr', { parent:grid });
this.ogl.shipsList.forEach(type =>
{
if(data[type])
{
Util.addDom('div', { class:`ogl_icon ogl_${type}`, child:Util.formatToUnits(data[type]), parent:grid });
hasShips = true;
}
});
if(hasShips) Util.addDom('hr', { parent:grid });
['artefact', 'lifeform1', 'lifeform2', 'lifeform3', 'lifeform4'].forEach(type =>
{
if(data[type])
{
Util.addDom('div', { class:`ogl_icon ogl_${type}`, child:Util.formatToUnits(data[type]), parent:grid });
hasLifeforms = true;
}
});
if(hasLifeforms) Util.addDom('hr', { parent:grid });
['blackhole', 'trader', 'early', 'late', 'pirate', 'alien'].forEach(type =>
{
if(data[type])
{
Util.addDom('div', { 'data-resultType':type, class:`ogl_icon ogl_${type}`, child:Util.formatToUnits(data[type]), parent:grid });
hasExpeditions = true;
}
});
if(hasExpeditions) Util.addDom('hr', { parent:grid });
}
this.currentValue = this.hideTimer;
this.notification.classList.add('ogl_active');
clearInterval(this.interval);
this.interval = setInterval(() => this.updateClock(), this.step);
}
addToQueue(message, success, data)
{
this.blocks.push({ time:serverTime.getTime(), message:message, data:data, success:(success = success === true ? 1 : success === false ? -1 : 0) });
this.blocks.sort((a, b) => a.time - b.time);
this.blocks = this.blocks.filter(e => serverTime.getTime() < e.time + this.hideTimer);
this.open();
}
updateClock()
{
this.currentValue -= this.step;
this.clock.value = this.currentValue;
if(this.currentValue < 0) this.close();
}
close()
{
clearInterval(this.interval);
this.notification.classList.remove('ogl_active');
}
triggerBrowserNotification(data)
{
if(Notification.permission === 'granted')
{
const notif = new Notification(`OGame - ${this.ogl.server.name}.${this.ogl.server.lang}`,
{
body:data.message,
requireInteraction:true,
});
notif.addEventListener('show', () =>
{
delete this.ogl.db.browserNotificationList[data.id];
});
}
/*GM_notification(
{
title:`OGame - ${this.ogl.server.name}.${this.ogl.server.lang}`,
text:notif.message
});
delete this.ogl.db.browserNotificationList[notif.id];*/
}
addNotification(data, sender)
{
if(Notification.permission === 'default')
{
Notification.requestPermission().then(permission =>
{
if(Notification.permission === 'granted')
{
this.addNotification(data, sender);
}
});
}
else if(Notification.permission === 'granted')
{
if(!this.ogl.db.browserNotificationList[data.id])
{
this.ogl.db.browserNotificationList[data.id] = data;
sender.classList.add('ogl_active');
}
else
{
delete this.ogl.db.browserNotificationList[data.id];
sender.classList.remove('ogl_active');
sender.classList.remove('ogl_altered');
}
}
else
{
alert('You have to enable notifications in your browser setting !');
}
}
testNotification()
{
const browserNotification = {};
browserNotification.id = '-99999999';
browserNotification.arrivalTime = serverTime.getTime() + 10000;
browserNotification.message = `Test`;
this.ogl.db.browserNotificationList[browserNotification.id] = browserNotification;
}
}
class PopupManager extends Manager
{
load()
{
this.popup = Util.addDom('div', {class:'ogl_popup', parent:document.body});
this.popup.addEventListener('click', event =>
{
if(event.target === this.popup) this.close();
});
//visualViewport.addEventListener('resize', () => this.updatePosition());
//visualViewport.addEventListener('scroll', () => this.updatePosition());
}
open(dom, canShare)
{
tippy.hideAll();
this.popup.innerText = '';
if(!dom) return;
Util.addDom('div',
{
class:'ogl_close material-icons',
child:'close',
prepend:dom,
onclick:() =>
{
this.close();
}
});
if(canShare)
{
Util.addDom('div',
{
class:'ogl_share material-icons',
child:'photo_camera',
prepend:dom,
onclick:event =>
{
event.target.classList.add('ogl_disabled');
Util.takeScreenshot(this.popup.querySelector('div'), event.target, `ogl_${this.ogl.server.id}_${this.ogl.server.lang}_empire_${serverTime.getTime()}`);
}
});
}
dom.classList.add('ogl_popupContent');
this.popup.appendChild(dom);
this.popup.classList.add('ogl_active');
initTooltips();
}
close()
{
this.popup.classList.remove('ogl_active');
}
updatePosition()
{
const div = this.popup;
div.style.top = visualViewport.offsetTop + 'px';
div.style.height = visualViewport.height - 25 + 'px';
div.style.left = visualViewport.offsetLeft + 'px';
div.style.width = visualViewport.width + 'px';
}
isActive()
{
return this.popup.classList.contains('ogl_active');
}
}
class MessageManager extends Manager
{
load()
{
this.initSpyTable();
if(this.ogl.page !== 'messages') return;
this.counterSpiesList = [];
this.initMessageDB();
this.tabID = this.tabID || 20;
this.deleteList = [];
this.dialogDelay = 0;
Util.overWrite('paginatorPrevious', unsafeWindow.ogame.messages, false, () => { if(this.tabID != 20) this.checkTab() });
Util.overWrite('paginatorNext', unsafeWindow.ogame.messages, false, () => { if(this.tabID != 20) this.checkTab() });
Util.overWrite('paginatorFirst', unsafeWindow.ogame.messages, false, () => { if(this.tabID != 20) this.checkTab() });
Util.overWrite('paginatorLast', unsafeWindow.ogame.messages, false, () => { if(this.tabID != 20) this.checkTab() });
// occurs if OGL loads after ogame messages
if(document.querySelector('.msg'))
{
this.checkTab();
}
setTimeout(() => this.checkBoard(), 400);
this.addBoardTab();
}
initMessageDB()
{
this.messageDBName = this.ogl.DBName + '_messages';
const data = GM_getValue(this.messageDBName) || {};
this.messageDB = typeof data === typeof '' ? JSON.parse(data) : {};
}
saveMessagesDB()
{
if(this.ogl.page !== 'messages' && this.ogl.page !== 'fleetdispatch') return;
try
{
GM_setValue(this.messageDBName, JSON.stringify(this.messageDB));
}
catch(error)
{
console.log(error);
}
}
purgeMessageDB()
{
this.messageDB = {};
this.saveMessagesDB();
}
checkTab()
{
document.querySelector('.ogl_boardMessageTab')?.classList.remove('marker');
this.readMessagesData();
if(this.tabID == 20 && this.ogl.db.options.displaySpyTable)
{
Util.runAsync(() => this.loadSpyTable());
}
}
initSpyTable()
{
this.spytable = Util.addDom('div', { class:'ogl_spytable' });
this.ogl.db.spytableFilters = this.ogl.db.spytableFilters || { age:'ASC', rawCoords:false, playerName:false, wave1:false, fleetValue:false, defValue:false };
this.filterOrder = { age:'DESC', rawCoords:'ASC', playerName:'ASC', wave1:'DESC', fleetValue:'DESC', defValue:'DESC' };
Util.addDom('div',
{
class:'ogl_spyHeader',
parent:this.spytable,
child:
`
<b class="ogl_textCenter">#</b>
<b class="material-icons" data-filter="age">schedule</b>
<b class="ogl_textCenter">*</b>
<b class="ogl_textCenter"> </b>
<b data-filter="rawCoords">coords</b>
<b data-filter="playerName">name</b>
<b data-filter="wave1">${this.ogl.db.options.spyTableMSU ? 'MSU' : 'loot'}</b>
<b class="material-icons" data-filter="fleetValue">rocket_launch</b>
<b class="material-icons" data-filter="defValue">security</b>
<b class="ogl_spytableSettings">
<div class="material-icons ogl_button tooltip" title="Clean reports" data-action="broom">mop</div>
<div class="material-icons ogl_button tooltip" title="Ignore rules" data-action="ignore" data-label="0">block</div>
<div class="material-icons ogl_button tooltip" title="Highlight rules" data-action="highlight" data-label="0">star</div>
</b>
`,
onclick:event =>
{
let broom = event.target.dataset?.action == 'broom';
let ignore = event.target.dataset?.action == 'ignore';
let highlight = event.target.dataset?.action == 'highlight';
let filter = event.target.getAttribute('data-filter');
if(!filter && !ignore && !highlight && !broom) return;
if(filter)
{
Object.keys(this.ogl.db.spytableFilters).forEach(key =>
{
if(filter.replace('DESC', '') == key)
{
if(this.ogl.db.spytableFilters[key] == 'ASC')
{
this.ogl.db.spytableFilters[key] = 'DESC';
}
else if(this.ogl.db.spytableFilters[key] == 'DESC')
{
this.ogl.db.spytableFilters[key] = 'ASC';
}
else
{
this.ogl.db.spytableFilters[key] = this.filterOrder[key];
}
}
else this.ogl.db.spytableFilters[key] = false;
});
this.loadSpyTable();
}
if(ignore || highlight)
{
this.openSpyTableRules(event.target.dataset.action);
}
if(broom)
{
this.counterSpiesList.forEach(e => this.deleteList.push(e));
this.counterSpiesList = [];
this.loadSpyTable(false, true);
}
}
});
}
readMessagesData()
{
this.ptreCounterSpies = {};
const messageIds = [];
const xml = new DOMParser().parseFromString(ogame.messages.content.join(''), 'text/html');
xml.querySelectorAll('.msg').forEach(xmlLine =>
{
const rawData = xmlLine.querySelector('.rawMessageData');
if(!rawData) return;
const message = {};
message.id = xmlLine.getAttribute('data-msg-id');
message.globalTypeID = rawData.dataset.rawMessagetype;
message.date = this.ogl._time.getObj(parseInt(rawData.dataset.rawTimestamp || rawData.dataset.rawDatetime || 0) * 1000, 'client');
message.api = rawData.dataset.rawHashcode;
message.playerID = rawData.dataset.rawTargetplayerid;
messageIds.push(message.id);
const dom = document.querySelector(`[data-msg-id="${message.id}"]`);
if(dom)
{
this.ogl._time.update(false, dom.querySelector('.msgDate:not(.ogl_updated)'));
if(dom.querySelector('.icon_apikey') && message.api) dom.querySelector('.icon_apikey').setAttribute('data-api-code', message.api);
}
// clean counter spies
if(this.ogl.db.options.autoCleanCounterSpies && message.playerID == this.ogl.account.id)
{
this.deleteList.push(message.id);
}
if(this.messageDB[message.id] && this.messageDB[message.id].msu !== undefined)
{
// we need to update "attacked" state if the report already exist
this.messageDB[message.id].isAttacked = parseInt(rawData.dataset.rawAttacking || '0');
return;
}
if((this.tabID == 20 || this.tabID == 25) && this.ogl.db.options.displaySpyTable) // spies
{
this.readSpyData(message, xmlLine, rawData, dom);
}
else if(this.tabID == 21) // combat
{
if(message.globalTypeID == 25) this.readCombatData(message, xmlLine, rawData, dom);
else if(message.globalTypeID == 48) this.readProbeData(message, xmlLine, rawData, dom);
}
else if(this.tabID == 22) // expeditions & discoveries
{
this.readExpeditionData(message, xmlLine, rawData, dom);
}
else if(this.tabID == 23 || this.tabID == 24) // cargo & debris
{
this.readOtherData(message, xmlLine, rawData, dom);
}
});
if(this.tabID == 20)
{
// clean old report then update changes
this.messageDB = Object.fromEntries(Object.entries(this.messageDB).filter(([id]) => messageIds.includes(id)));
this.saveMessagesDB();
if(Object.keys(this.ptreCounterSpies).length > 0)
{
this.ogl.PTRE.postActivities(this.ptreCounterSpies);
this.ptreCounterSpies = {};
}
}
if(this.tabID == 21 || this.tabID == 22 || this.tabID == 24)
{
this.ogl._stats.showMiniRecap();
}
initTooltips();
this.ogl._fleet.checkSendShips();
}
readSpyData(message, xmlLine, rawData, dom)
{
const rawStatusClass = Array.from(xmlLine.querySelector(`.playerName span[class*="status_"]`)?.classList || []).filter(e => e.startsWith('status_'))[0];
message.planetID = rawData.dataset.rawTargetplanetid;
message.isCounterSpy = message.playerID == this.ogl.account.id;
message.playerName = rawData.dataset.rawPlayername;
message.playerStatus = this.ogl.playerStatus.find(e => e.class == rawStatusClass)?.defaultTag || 'n';
message.targetType = rawData.dataset.rawTargetplanettype == 1 ? 'planet' : 'moon';
message.targetTypeID = rawData.dataset.rawTargetplanettype;
message.coords = rawData.dataset.rawCoordinates;
message.rawCoords = Util.coordsToID(message.coords);
message.age = parseInt(message.date.server);
message.isActive = parseInt(rawData.dataset.rawActive);
message.activity = parseInt(rawData.dataset.rawActivity);
message.resources = parseInt(rawData.dataset.rawResources);
message.metal = parseInt(rawData.dataset.rawMetal);
message.crystal = parseInt(rawData.dataset.rawCrystal);
message.deut = parseInt(rawData.dataset.rawDeuterium);
message.msu = Util.getMSU(message.metal, message.crystal, message.deut, this.ogl.db.options.msu);
message.hiddenFleet = rawData.dataset.rawHiddenships == 1 ? true : false;
message.hiddenDef = rawData.dataset.rawHiddendef == 1 ? true : false;
message.fleet = rawData.dataset.rawFleet == '-' ? {} : JSON.parse(rawData.dataset.rawFleet || '{}');
message.def = rawData.dataset.rawDefense == '-' ? {} : JSON.parse(rawData.dataset.rawDefense || '{}');
message.loot = parseInt(rawData.dataset.rawLoot);
message.fleetValue = message.hiddenFleet ? -1 : parseInt(rawData.dataset.rawFleetvalue || 0);
message.defValue = message.hiddenDef ? -1 : parseInt(rawData.dataset.rawDefensevalue || 0);
message.techs = rawData.dataset.rawResearch == '-' ? {} : JSON.parse(rawData.dataset.rawResearch || '{}');
message.isAttacked = parseInt(rawData.dataset.rawAttacking);
if(message.playerID == 99999) return; // p16
if(message.activity == -1 || !message.isActive && message.activity < 15) message.activity = 60;
if(message.isCounterSpy)
{
message.sourceID = rawData.dataset.rawSourceplayerid;
message.sourceCoords = rawData.dataset.rawSourceplanetcoordinates;
const coords = message.sourceCoords.split(':');
if(this.ogl.ptreKey)
{
this.ptreCounterSpies[message.id] = {};
this.ptreCounterSpies[message.id].player_id = message.sourceID;
this.ptreCounterSpies[message.id].teamkey = this.ogl.ptreKey;
this.ptreCounterSpies[message.id].galaxy = coords[0];
this.ptreCounterSpies[message.id].system = coords[1];
this.ptreCounterSpies[message.id].position = coords[2];
this.ptreCounterSpies[message.id].spy_message_ts = parseInt(message.date.client);
this.ptreCounterSpies[message.id].moon = {};
this.ptreCounterSpies[message.id].activity = '*';
this.ptreCounterSpies[message.id].moon.activity = '*';
this.counterSpiesList.push(message.id);
const dom = document.querySelector(`.msg[data-msg-id="${message.id}"] message-footer-actions`);
if(dom && !dom.querySelector('.ogl_checked'))
{
Util.addDom('div', { class:'material-icons ogl_checked ogl_mainIcon tooltip', child:'ptre', title:this.ogl._lang.find('ptreMessageDone'), parent:dom });
}
}
if(dom)
{
setTimeout(() => this.ogl._ui.turnIntoPlayerLink(message.sourceID, dom.querySelector('.tooltipCustom.player')));
}
}
else
{
if(this.ogl.db.udb[message.playerID])
{
if(message.techs?.[124]) this.ogl.db.udb[message.playerID].astro = message.techs[124];
this.ogl.db.udb[message.playerID].name = message.playerName;
this.ogl.db.udb[message.playerID].status = message.playerStatus;
this.ogl.db.udb[message.playerID].liveUpdate = serverTime.getTime();
}
const resources = message.resources;
const loot = message.loot / 100;
for(let i = 1; i <= 6; i++)
{
message['wave' + i] = Math.floor(resources * Math.pow(1 - loot, i - 1) * loot);
}
this.messageDB[message.id] = message;
}
}
readExpeditionData(message, xmlLine, rawData, dom)
{
message.lifeform = parseInt(rawData.dataset.rawLifeform || 0);
message.expeditionResult = rawData.dataset.rawExpeditionresult;
message.resources = JSON.parse(rawData.dataset.rawResourcesgained?.replace('deuterium', 'deut')?.replace('darkMatter', 'dm') || '{}');
message.artefact = parseInt(rawData.dataset.rawArtifactsfound || 0);
message.lfXP = parseInt(rawData.dataset.rawLifeformgainedexperience || 0);
message.ships = {};
message.delay = JSON.parse(rawData.dataset.rawNavigation || '{ "returnTimeAbsoluteIncreaseHours":0, "returnTimeMultiplier":1 }');
message.item = JSON.parse(rawData.dataset.rawItemsgained || '{}');
message.depletion = parseInt(rawData.dataset.rawDepletion || 0);
message.size = parseInt((rawData.dataset.rawSize || rawData.dataset.rawArtifactssize || '-1').replace('normal', '2').replace('big', '1').replace('huge', '0'));
message.shipLost = {};
for(let [lossID, amount] of Object.entries(JSON.parse(rawData.dataset.rawShipslost || '{}')))
{
message.shipLost[-lossID] = amount;
}
const backListedSize = ['nothing', 'trader', 'blackhole', 'lifeform'];
if(message.globalTypeID == 61) // discoveries
{
if(message.artefact > 0) message.resultType = 'artefact';
else if(message.lfXP > 0) message.resultType = 'lifeform';
else message.resultType = 'nothing';
}
else
{
if(message.expeditionResult == 'ressources') message.resultType = 'resource';
else if(message.expeditionResult == 'darkmatter') message.resultType = 'darkmatter';
else if(message.expeditionResult == 'nothing') message.resultType = 'nothing';
else if(message.expeditionResult == 'shipwrecks') message.resultType = 'ship';
else if(message.expeditionResult == 'trader') message.resultType = 'trader';
else if(message.expeditionResult == 'items') message.resultType = 'item';
else if(message.expeditionResult == 'fleetLost') message.resultType = 'blackhole';
else if(message.expeditionResult == 'navigation' && message.delay.returnTimeMultiplier < 1) message.resultType = 'early';
else if(message.expeditionResult == 'navigation' && (message.delay.returnTimeMultiplier > 1 || message.delay.returnTimeAbsoluteIncreaseHours >= 0)) message.resultType = 'late';
else if(message.expeditionResult == 'combatPirates') message.resultType = 'pirate';
else if(message.expeditionResult == 'combatAliens') message.resultType = 'alien';
}
Object.entries(JSON.parse(rawData.dataset.rawTechnologiesgained || '{}')).forEach(ship =>
{
message.ships[ship[0]] = ship[1].amount;
});
message.gain = { ...message.resources, ...message.ships, ...{artefact:message.artefact}, ...{['lifeform'+message.lifeform]:message.lfXP}, ...{resultType:message.resultType} };
if(message.resultType)
{
if(backListedSize.indexOf(message.resultType) >= 0) message.size = -1;
this.summarize(message);
this.statify(message);
}
}
readOtherData(message, xmlLine, rawData, dom)
{
message.coords = rawData.dataset.rawCoords;
message.debris = JSON.parse(rawData.dataset.rawRecycledresources || '{}');
message.cargo = JSON.parse(rawData.dataset.rawCargo || '{}');
message.gain = {};
Object.entries(message.debris).forEach(entry =>
{
if(entry[1] > 0)
{
message.gain[entry[0].replace('deuterium', 'deut')] = entry[1];
message.resultType = 'debris';
}
});
message.debris = false;
Object.entries(message.cargo).forEach(entry =>
{
if(entry[1] > 0)
{
message.gain[entry[0].replace('deuterium', 'deut')] = entry[1];
message.resultType = 'cargo';
}
});
if(message.resultType)
{
this.summarize(message);
if(this.tabID == 24) this.statify(message);
}
}
readProbeData(message, xmlLine, rawData, dom)
{
message.coords = rawData.dataset.rawCoords;
message.gain = { metal:0, crystal:0, deut:0 };
// we need to work with negative keys
message.shipLost = Object.fromEntries(Object.entries(JSON.parse(rawData.dataset.rawShipslost || "{}")).map(([k, v]) => [`-${k}`, v]));
this.summarize(message);
if(Object.keys(message.shipLost).length > 1 || !('-210' in message.shipLost)) // 1 turn (not probe only) battle
{
this.statify(message);
}
}
readCombatData(message, xmlLine, rawData, dom)
{
message.coords = rawData.dataset.rawCoords;
message.defenderSpace = JSON.parse(rawData.dataset.rawDefenderspaceobject || '{}');
message.fleets = JSON.parse(rawData.dataset.rawFleets || '{}');
message.rounds = JSON.parse(rawData.dataset.rawCombatrounds || '{}');
message.result = JSON.parse(rawData.dataset.rawResult || '{}');
message.gain = { metal:0, crystal:0, deut:0 };
message.shipLost = {};
message.resultType = 'raid';
message.isOwnPlanet = message.defenderSpace.owner?.id == this.ogl.account.id;
message.probeOnly = false;
if(!message.api || message.globalTypeID == 35) return;
const ownFleets = message.fleets?.filter(fleet => fleet.player?.id == this.ogl.account.id).map(fleet => fleet.fleetId);
const ownSides = message.fleets?.filter(fleet => fleet.player?.id == this.ogl.account.id).map(fleet => fleet.side);
const lastRound = message.rounds[message.rounds.length - 1];
message.isAttacker = ownSides.indexOf('attacker') >= 0;
message.isDefender = ownSides.indexOf('defender') >= 0;
message.isWinner = ownSides.indexOf(message.result.winner) >= 0;
message.noWinner = message.result.winner == 'none';
if(message.isWinner && message.isAttacker)
{
message.gain.metal = message.result.loot.resources.find(line => line.resource == 'metal')?.amount;
message.gain.crystal = message.result.loot.resources.find(line => line.resource == 'crystal')?.amount;
message.gain.deut = message.result.loot.resources.find(line => line.resource == 'deuterium')?.amount;
}
if(!message.isWinner && !message.noWinner && message.isOwnPlanet)
{
message.gain.metal = -message.result.loot.resources.find(line => line.resource == 'metal')?.amount;
message.gain.crystal = -message.result.loot.resources.find(line => line.resource == 'crystal')?.amount;
message.gain.deut = -message.result.loot.resources.find(line => line.resource == 'deuterium')?.amount;
}
const attackerShips = message.fleets?.filter(fleet => fleet.side == 'attacker').map(fleet => fleet.combatTechnologies).reduce((acc, obj) => ({...acc, ...obj}), {});
const defenderShips = message.fleets?.filter(fleet => fleet.side == 'defender').map(fleet => fleet.combatTechnologies).reduce((acc, obj) => ({...acc, ...obj}), {});
if(Object.values(attackerShips).length == 1 && attackerShips[0].technologyId == 210 && (message.gain.metal + message.gain.crystal + message.gain.deut == 0)) message.probeOnly = true;
if(Object.values(defenderShips).length == 1 && defenderShips[0].technologyId == 210 && (message.gain.metal + message.gain.crystal + message.gain.deut == 0)) message.probeOnly = true;
if(lastRound)
{
lastRound.fleets.forEach(fleet =>
{
if(ownFleets.indexOf(fleet.fleetId) >= 0)
{
fleet.technologies.forEach(tech =>
{
if(tech.destroyedTotal) message.shipLost[-tech.technologyId] = tech.destroyedTotal;
});
}
});
}
if(message.isDefender && message.isOwnPlanet)
{
message.result.repairedTechnologies.forEach(repaired =>
{
message.shipLost[-repaired.technologyId] -= repaired.amount;
});
}
if(message.result?.debris?.resources)
{
message.debris = {};
message.result.debris.resources.forEach(e =>
{
if(e.remaining > 0)
{
message.debris[e.resource?.replace('deuterium', 'deut')] = e.remaining;
}
});
}
if(dom)
{
Util.addDom('div',
{
class:'ogl_messageButton tooltip',
title:'Convert this battle',
parent:dom.querySelector('message-footer-actions'),
child:'C',
onclick:() => window.open(Util.genConverterLink(this.ogl, message.api), '_blank')
});
}
if(message.resultType)
{
this.summarize(message);
if(!message.probeOnly) this.statify(message);
}
}
loadSpyTable(isOutdated, forceClean)
{
const rulesCount = Object.values(this.ogl.db.options.spyTableRules || {}).filter(item => item.active).reduce((acc, item) => (acc[item.type || 'ignore'] = (acc[item.type || 'ignore'] || 0) + 1, acc), { ignore:0, highlight:0 });
Object.entries(rulesCount).forEach(entry =>
{
this.spytable.querySelector(`.ogl_spyHeader [data-action="${entry[0]}"]`).dataset.label = entry[1];
});
const wrapper = Util.addDom('div', { class:'ogl_lineWrapper' });
if(isOutdated) this.spytable.classList.add('ogl_outdated');
this.spySumLine = Util.addDom('div', { class:'ogl_spyLine ogl_spySum' });
this.spyRecap = { count:0, value:0 };
const filter = ([Object.entries(this.ogl.db.spytableFilters).find(e => e[1] != false)] || [['age', 'ASC']])[0];
let isDesc = filter[1] == 'DESC';
let filterKey = filter[0];
this.spytable.querySelectorAll('.ogl_spyHeader .ogl_active').forEach(e => e.classList.remove('ogl_active'));
this.spytable.querySelector(`.ogl_spyHeader [data-filter="${filter[0]}"]`)?.classList.add('ogl_active');
this.nextTarget = false;
const currentPlanet = (([g, s, p]) => ({ galaxy: g, system: s, position: p }))(this.ogl.currentPlanet.obj.coords.split(':').map(Number));
const shouldIgnore = message =>
{
let resultFlags = 0;
for (const rule of this.ogl.db.options.spyTableRules)
{
if(!rule.active) continue;
const ruleType = rule.type || 'ignore';
let isRuleSatisfied = false;
let value;
if (rule.field === 'distance')
{
const [g, s, p] = message.coords.split(':').map(Number);
const targetPlanet = { galaxy: g, system: s, position: p };
const targetIsInRange = Util.planetIsInRange(this.ogl, currentPlanet, targetPlanet, rule.value);
if(rule.operator === '>')
{
isRuleSatisfied = !targetIsInRange;
}
else
{
isRuleSatisfied = targetIsInRange;
}
}
if(rule.field === 'total') value = message.wave1 + (message.fleetValue * this.ogl.db.serverData.debrisFactor / 100);
else if(rule.field === 'resources') value = message.wave1;
else if(rule.field === 'fleet') value = message.fleetValue;
else if(rule.field === 'def') value = message.defValue;
else if(rule.field === 'metal') value = message.metal;
else if(rule.field === 'crystal') value = message.crystal;
else if(rule.field === 'deut') value = message.deut;
if((rule.operator === '<' && value < rule.value) || (rule.operator === '>' && value > rule.value))
{
isRuleSatisfied = true;
}
if(isRuleSatisfied)
{
if (ruleType === 'ignore')
{
resultFlags |= 1;
}
else if (ruleType === 'highlight')
{
resultFlags |= 2;
}
}
}
return resultFlags;
}
const list = Object.values(this.messageDB).map(message =>
{
const rulesState = shouldIgnore(message);
if((rulesState & 1) > 0) message.ignored = true;
else message.ignored = false;
if((rulesState & 2) > 0) message.highlighted = true;
else message.highlighted = false;
if(!isOutdated && message.ignored && !message.highlighted && (this.ogl.db.options.autoCleanReports || forceClean))
{
this.deleteList.push(message.id);
}
return message;
});
list.sort((a, b) =>
{
if(a[filterKey] === undefined || b[filterKey] === undefined) filterKey = 'age';
if(a.ignored && !b.ignored) return 1;
if(!a.ignored && b.ignored) return -1;
const valA = this.ogl.db.options.spyTableMSU && filterKey == 'wave1' ? a.msu : a[filterKey];
const valB = this.ogl.db.options.spyTableMSU && filterKey == 'wave1' ? b.msu : b[filterKey];
if((valA == null && valA !== 0) || (valB == null && valB !== 0)) return 0;
if(isNaN(valA) || isNaN(valB))
{
return isDesc ?
String(valB).localeCompare(String(valA)) :
String(valA).localeCompare(String(valB));
}
return isDesc ? valB - valA : valA - valB;
});
if(this.deleteList.length > 0)
{
this.deleteList = [...new Set(this.deleteList)];
this.deleteMessageList(this.deleteList);
this.deleteList = [];
}
list.forEach(message =>
{
const delta = serverTime.getTime() - message.date.server;
let age = delta;
if(age > 86400000) age = Math.floor(age / (1000 * 3600 * 24)) + LocalizationStrings.timeunits.short.day;
else if(age > 3600000) age = Math.floor(age / (1000 * 3600)) + LocalizationStrings.timeunits.short.hour;
else age = Math.floor(age / (1000 * 60)) + LocalizationStrings.timeunits.short.minute;
const bonusFleetSpeed = this.ogl.server.warFleetSpeed == 1 ? .042 : 0;
const bonusCargo = 1 + (Math.ceil(delta / 3600000) * .042) + bonusFleetSpeed; // +4.2% cargo per hour (100% per 24h)
const requiredShips = this.ogl._fleet.shipsForResources(this.ogl.db.options.defaultShip, Math.round(message.wave1 * bonusCargo));
const line = Util.addDom('div', { class:'ogl_spyLine', 'data-id':message.id, 'data-wave1':message.wave1, parent:wrapper });
const content = Util.addDom('div', { parent:line });
const more = Util.addDom('div', { parent:line, class:'ogl_more ogl_hidden' });
const coords = message.coords.split(':');
const timer = message.activity < 15 ? '*' : message.activity.toString().replace('60', '-');
const time = this.ogl.db.options.useClientTime ? message.date.client : message.date.server;
Util.addDom('span', { parent:content, class:'ogl_textCenter' });
Util.addDom('span', { child:age, parent:content, class:'ogl_textCenter tooltip', title:this.ogl._time.convertTimestampToDate(time, true).innerHTML });
const lootValue = this.ogl.db.options.spyTableMSU ? message.msu : message.wave1;
const timerDom = Util.addDom('span', { child:timer, parent:content, class:'ogl_textCenter' });
const targetType = Util.addDom('span', { parent:content });
const coordsDiv = Util.addDom('span', { child:`<span data-galaxy="${message.coords}">${message.coords}</<span>`, parent:content });
const nameContainer = Util.addDom('div', { parent:content, class:'ogl_spyTableName' });
const name = Util.addDom('a', { child:message.playerName, parent:nameContainer, class:'overlay', href:`https://${window.location.host}/game/index.php?page=componentOnly&component=messagedetails&messageId=${message.id}` });
const pin = Util.addDom('div', { parent:nameContainer });
const loot = Util.addDom('a', { child:Util.formatToUnits(lootValue), parent:content, class:'ogl_textRight ogl_loot', href:`https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=${message.targetTypeID}&mission=1&am${this.ogl.db.options.defaultShip}=${requiredShips}&oglmode=4&oglmsg=${message.id}` });
const fleet = Util.addDom('span', { child:Util.formatToUnits(message.fleetValue, 0).replace('-1', '?'), parent:content, class:'ogl_textRight' });
const def = Util.addDom('span', { child:Util.formatToUnits(message.defValue, 0).replace('-1', '?'), parent:content, class:'ogl_textRight' });
const actions = Util.addDom('span', { class:'ogl_actions', parent:content });
const messageDom = document.querySelector(`[data-msg-id="${message.id}"]`);
this.addSpyIcons(targetType, message.coords, message.targetType);
this.ogl._ui.addTagButton(coordsDiv, message.coords);
this.ogl._ui.addPinButton(pin, message.playerID);
this.ogl._ui.turnIntoPlayerLink(message.playerID, name, message.playerName);
if(message.activity < 15) timerDom.classList.add('ogl_danger');
else if(message.activity < 60) timerDom.classList.add('ogl_warning');
//if(message.wave1 >= this.ogl.db.options.resourceTreshold) loot.classList.add('ogl_important');
if(message.ignored) line.classList.add('ogl_ignored');
if(message.highlighted) line.classList.add('ogl_highlighted');
this.spyRecap.count++;
this.spyRecap.value += message.wave1;
if(message.fleetValue != 0) fleet.style.background = 'linear-gradient(192deg, #622a2a, #3c1717 70%)';
if(message.defValue != 0) def.style.background = 'linear-gradient(192deg, #622a2a, #3c1717 70%)';
// update message content actions
if(messageDom && !message.isCounterSpy && (!message.ignored || !this.ogl.db.options.autoCleanReports))
{
}
// next target (when you press enter)
if(!this.nextTarget && message.fleetValue == 0 && message.defValue == 0 && !message.isAttacked && !message.ignored)
{
this.nextTarget = message;
}
for(let i=1; i<7; i++)
{
const currentLoot = message['wave'+i];
const subLine = Util.addDom('div', { parent:more, child:`<div>${Util.formatToUnits(currentLoot)}</div>` });
this.ogl.fretShips.forEach(shipID =>
{
const shipsCount = this.ogl._fleet.shipsForResources(shipID, currentLoot * bonusCargo);
Util.addDom('a',
{
class:`ogl_icon ogl_${shipID}`,
parent:subLine,
child:shipsCount.toLocaleString('de-DE') || '0',
href:`https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=${message.targetTypeID}&mission=1&am${shipID}=${shipsCount}&oglmode=4&oglLazy=true`
});
});
}
Util.addDom('div',
{
class:'ogl_button material-icons ogl_moreButton tooltip',
title:'more waves',
parent:actions,
child:'more_horiz',
onclick:() => more.classList.toggle('ogl_hidden')
});
const attackBtn = Util.addDom('a',
{
class:'ogl_button material-icons tooltip',
title:'attack this position !',
parent:actions,
child:'swords',
href:`https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${coords[0]}&system=${coords[1]}&position=${coords[2]}&type=${message.targetTypeID}&mission=1`
});
if(message.isAttacked) Util.addDom('div', { class:'fleetAction fleetHostile', parent:attackBtn });
Util.addDom('div',
{
class:'ogl_button material-icons tooltip',
title:'Simulate',
parent:actions,
child:'play_arrow',
onclick:() => window.open(Util.genTrashsimLink(this.ogl, message.api), '_blank')
});
if(this.ogl.ptreKey)
{
// ptre action
Util.addDom('div',
{
class:'ogl_button material-icons tooltip',
title:'Send this report to PTRE',
parent:actions,
child:'ptre',
onclick:() => this.ogl.PTRE.postSpyReport(message.api)
});
}
// delete action
Util.addDom('div',
{
class:'ogl_button material-icons',
parent:actions,
child:'delete_forever',
onclick:() => this.deleteMessageList(message.id)
});
wrapper.appendChild(line);
});
if(!isOutdated) this.spytable.classList.remove('ogl_outdated');
this.spytable.querySelector('.ogl_lineWrapper')?.remove();
this.spytable.appendChild(wrapper);
document.querySelector('#messagecontainercomponent .content').insertBefore(this.spytable, document.querySelector('#messagecontainercomponent .content .messageContent'));
this.updateSumLine();
wrapper.appendChild(this.spySumLine);
initTooltips();
}
updateSumLine()
{
this.spySumLine.innerHTML = `<div><span></span><span></span><span></span><span></span><span></span><span>Total</span><span class="ogl_textRight">${Util.formatToUnits(this.spyRecap.value)}</span><span></span><span></span><div>`;
}
addSpyIcons(parent, coords, uniqueType, displayActivity)
{
coords = typeof coords == typeof '' ? coords = coords.split(':') : coords;
if(uniqueType == 'planet' || !uniqueType)
{
const planetIcon = Util.addDom('div', { class:'material-icons ogl_spyIcon tooltip', title:this.ogl._lang.find('spyPlanet'), 'data-spy-coords':`${coords[0]}:${coords[1]}:${coords[2]}:1`, child:'language', parent:parent, onclick:e => sendShips(6, coords[0], coords[1], coords[2], 1) });
const lastPlanetSpy = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.spy?.[0] || 0;
if(serverTime.getTime() - lastPlanetSpy < this.ogl.db.options.spyIndicatorDelay)
{
planetIcon.setAttribute('data-spy', 'recent');
planetIcon.setAttribute('title', 'recently spied');
}
if(displayActivity)
{
const activity = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.acti || [];
const isRecent = serverTime.getTime() - activity[2] < 3600000;
const activityDom = Util.addDom('span', { parent:planetIcon, child:isRecent ? activity[0] : '?' });
(activity[0] == '*' && isRecent) ? activityDom.classList.add('ogl_danger') : (activity[0] == 60 && isRecent) ? activityDom.classList.add('ogl_ok') : activityDom.classList.add('ogl_warning');
}
}
if(uniqueType == 'moon' || (!uniqueType && this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid))
{
const moonIcon = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid > 0 ? Util.addDom('div', { class:'material-icons ogl_spyIcon tooltip', title:this.ogl._lang.find('spyMoon'), 'data-spy-coords':`${coords[0]}:${coords[1]}:${coords[2]}:3`,child:'bedtime', parent:parent, onclick:e => sendShips(6, coords[0], coords[1], coords[2], 3) }) : Util.addDom('div', { parent:parent });
const lastMoontSpy = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.spy?.[1] || 0;
if(serverTime.getTime() - lastMoontSpy < this.ogl.db.options.spyIndicatorDelay)
{
moonIcon.setAttribute('data-spy', 'recent');
moonIcon.setAttribute('title', 'recently spied');
}
if(displayActivity && this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid > -1)
{
const activity = this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.acti || [];
const isRecent = serverTime.getTime() - activity[2] < 3600000;
const activityDom = Util.addDom('span', { parent:moonIcon, child:isRecent ? activity[1] : '?' });
(activity[1] == '*' && isRecent) ? activityDom.classList.add('ogl_danger') : (activity[1] == 60 && isRecent) ? activityDom.classList.add('ogl_ok') : activityDom.classList.add('ogl_warning');
}
}
if(!uniqueType && ! this.ogl.db.pdb[`${coords[0]}:${coords[1]}:${coords[2]}`]?.mid)
{
Util.addDom('div', { parent:parent });
}
}
openSpyTableRules(type)
{
const fields =
{
total:'Resources + Fleet debris',
resources:'Resources',
fleet:'Fleet debris',
def:'Defense',
metal:'Metal',
crystal:'Crystal',
deut:'Deut',
distance:'Distance (systems)'
}
const title = type == 'ignore' ? '<i class="material-icons ogl_danger">block</i> I want to ignore all reports with...' : '<i class="material-icons ogl_caution">star</i> I want to highlight all reports with...'
const container = Util.addDom('div', { class:'ogl_spyTableRules' });
const rulePicker = Util.addDom('fieldset', { parent:container, class:'ogl_addRule' });
const rulesList = Util.addDom('div', { parent:container, class:'ogl_rulesList' });
Util.addDom('legend', { parent:rulePicker, child:title });
const field = Util.addDom('select', { parent:rulePicker, class:'dropdownInitialized ogl_inputField', child:
`
<option value="total">${fields.total}</option>
<option value="resources">${fields.resources}</option>
<option value="fleet">${fields.fleet}</option>
<option value="def">${fields.def}</option>
<option value="metal">${fields.metal}</option>
<option value="crystal">${fields.crystal}</option>
<option value="deut">${fields.deut}</option>
<option value="distance">${fields.distance}</option>
`
});
const operator = Util.addDom('select', { parent:rulePicker, class:'dropdownInitialized ogl_inputField', child:
`
<option value="<"><</option>
<option value=">">></option>
`
});
const input = Util.addDom('input', { class:'ogl_inputCheck ogl_inputField', type:'text', parent:rulePicker, value:this.ogl.db.options.resourceTreshold });
Util.addDom('button', { parent:rulePicker, child:'<i>+</i> add a rule', class:'ogl_button', onclick:() =>
{
const value = parseInt(input.value.replace(/\D/g, '')) || 0;
this.ogl.db.options.spyTableRules.push({ field:field.value, operator:operator.value, value:value, active:true, type:type });
this.openSpyTableRules(type);
this.loadSpyTable();
}});
this.ogl.db.options.spyTableRules.filter(e => (e.type || 'ignore') == type).forEach(rule =>
{
const line = Util.addDom('div', { parent:rulesList });
Util.addDom('div', { child:fields[rule.field], parent:line });
Util.addDom('div', { child:rule.operator, parent:line });
Util.addDom('div', { child:Util.formatNumber(rule.value), parent:line });
const checkbox = Util.addDom('input', { type:'checkbox', class:'ogl_inputField', parent:line, onchange:() =>
{
rule.active = !rule.active;
checkbox.checked = rule.active;
this.loadSpyTable();
}});
if(rule.active) checkbox.checked = true;
Util.addDom('div', { class:'material-icons ogl_button ogl_danger', child:'delete', parent:line, onclick:() =>
{
const rulesTypeIndex = this.ogl.db.options.spyTableRules.findIndex(r => r === rule);
this.ogl.db.options.spyTableRules.splice(rulesTypeIndex, 1);
this.openSpyTableRules(type);
this.loadSpyTable();
}});
});
this.ogl._popup.open(container);
setTimeout(() => Util.formatInput(input));
}
summarize(message)
{
const messageDom = document.querySelector(`[data-msg-id="${message.id}"]`);
if(!messageDom) return;
if(messageDom.querySelector('.ogl_battle')) messageDom.querySelector('.ogl_battle').remove();
if(!messageDom.querySelector(`.ogl_checked`)) Util.addDom('div', { class:'material-icons ogl_checked ogl_mainIcon tooltip', child:'oglight_simple', title:this.ogl._lang.find('oglMessageDone'), parent:messageDom.querySelector('message-footer-actions') });
const tooltipContent = Util.addDom('ul', { class:'ogl_battleTooltip' });
const recap = Util.addDom('div', { class:'ogl_battle', 'data-resultType':message.resultType || 'unknown', before:messageDom.querySelector('.msg_actions'), onclick:() =>
{
if(recap.classList.contains('ogl_clickable')) messageDom.querySelector('.msgContent').classList.toggle('ogl_hidden');
}});
const gainSum = Object.values(message.gain).reduce((a, b) => parseInt(a) || 0 + parseInt(b) || 0, 0);
const gains = { ...message.gain };
Object.entries(message.shipLost || {}).forEach(entry =>
{
if(!isNaN(entry[0]) && entry[0] < 0)
{
Object.entries(Datafinder.getTech(-entry[0])).forEach(res => gains[res[0]] = (gains[res[0]] || 0) - res[1] * entry[1]);
}
});
Object.entries(gains).forEach(entry =>
{
if(!isNaN(entry[1]) && entry[1] !== 0) Util.addDom('div', { class:`ogl_icon ogl_${entry[0]}`, child:Util.formatToUnits(entry[1], false, true), parent:recap });
else if(gainSum == 0 && isNaN(entry[1])) Util.addDom('div', { class:`ogl_icon ogl_${entry[0]}`, child:this.ogl._lang.find(entry[1]), parent:recap });
});
if(message.debris && (message.debris.metal || 0) + (message.debris.crystal || 0) + (message.debris.deut || 0) != 0)
{
const recapDebris = Util.addDom('div', { class:'ogl_battle ogl_clickable', 'data-resultType':'debris', before:messageDom.querySelector('.msg_actions'), onclick:() => messageDom.querySelector('.msgContent').classList.toggle('ogl_hidden')});
Object.entries(message.debris).forEach(entry =>
{
if(!isNaN(entry[1]) && entry[1] !== 0) Util.addDom('div', { class:`ogl_icon ogl_${entry[0]}`, child:Util.formatToUnits(entry[1]), parent:recapDebris });
});
}
if(gains.metal + gains.crystal + gains.deut == 0)
{
Util.addDom('div', { class:`ogl_icon`, child:'-', parent:recap });
}
if(message.resultType)
{
recap.classList.add('ogl_clickable');
if(message.globalTypeID == 41 || message.globalTypeID == 61 || message.globalTypeID == 32) messageDom.querySelector('.msgContent').classList.add('ogl_hidden');
}
if(message.item?.[0])
{
recap.classList.add('tooltip');
tooltipContent.appendChild(Util.addDom('li', { child:`Item : <b class="ogl_highlight">${message.item?.[0].name}</b>` }));
}
if(message.size >= 0)
{
const sizes = { 0:'Extraordinary', 1:'Especial', 2:'Normal' };
recap.classList.add('tooltip');
tooltipContent.appendChild(Util.addDom('li', { child:`Size : <b data-size-value="${message.size}">${sizes[message.size]}</b>` }));
recap.setAttribute('data-size', message.size);
//Util.addDom('div', { class:'material-icons', child:'trophy', 'data-size-value':message.size, parent:messageDom.querySelector('.msgTitle') });
}
if(message.depletion > 0)
{
recap.classList.add('tooltip');
tooltipContent.appendChild(Util.addDom('li', { child:`Depletion value : <b data-depletion-value="${message.depletion}">${message.depletion}</b>` }));
recap.setAttribute('data-depletion', message.depletion);
}
if(message.itemName)
{
recap.innerText = message.itemName;
}
if(tooltipContent.innerText != '') recap.title = tooltipContent.innerHTML;
}
statify(message)
{
const isP16 = (message.coords || '0:0:0').split(':')[2] == 16;
const isPiralien = (message.globalTypeID == 25 || message.globalTypeID == 48) && isP16;
const isDebris16 = message.globalTypeID == 32 && isP16;
// expe, raid, discovery, debris, debris16, blackhole
const type =
isPiralien ? 'expe' :
isDebris16 ? 'debris16' :
message.globalTypeID == 41 ? 'expe' :
message.globalTypeID == 61 ? 'discovery' :
(message.globalTypeID == 25 || message.globalTypeID == 48) ? 'raid' :
message.globalTypeID == 32 ? 'debris' : false;
// resource, ship, pirate, alien, late, early, darkmatter, blackhole, nothing, item, trader
const occurence =
message.globalTypeID == 41 ? message.resultType :
message.globalTypeID == 61 ? message.resultType : false;
if(type)
{
const stats = this.ogl._stats.getDayStats(this.ogl._time.timeToKey(message.date.server));
if(this.ogl.db.options.debugMode)
{
const debugText = stats.ids?.indexOf(message.id) > -1 ? 'OLD ENTRY' : 'NEW ENTRY';
const dom = document.querySelector(`[data-msg-id="${message.id}"]`);
if(dom) Util.addDom('div', { style:'background:rgba(0,0,0,.8); position:absolute; bottom:30px; right:10px; text-align:center; color:var(--ogl);', child:debugText, parent:dom });
}
if(stats.ids?.indexOf(message.id) > -1) return;
const notificationData = {};
if(message.id)
{
stats.ids = stats.ids || [];
stats.ids.push(message.id);
}
stats[type] = stats[type] || {};
if(!isPiralien) stats[type].count = (stats[type].count || 0) + 1;
if(occurence)
{
stats[type].occurence = stats[type].occurence || {};
stats[type].occurence[occurence] = (stats[type].occurence[occurence] || 0) + 1;
}
if(message.shipLost)
{
message.gain = { ...message.gain, ...message.shipLost };
}
for(let [gainID, amount] of Object.entries(message.gain))
{
if(!isNaN(amount) && amount != 0)
{
const sign = !isNaN(gainID) && gainID < 0 ? -1 : 1;
const gid = !isNaN(gainID) ? Math.abs(gainID) : gainID;
notificationData[gid] = (notificationData[gid] || 0) + amount * sign;
stats[type].gain = stats[type].gain || {};
stats[type].gain[gainID] = (stats[type].gain[gainID] || 0) + (amount == '?' ? 1 : amount);
}
else if(gainID == 'resultType')
{
notificationData[amount] = (notificationData[amount] || 0) + 1;
}
}
if(!document.querySelector('#ogame-tracker-menu')) this.ogl._notification.addToQueue(false, undefined, notificationData);
}
}
deleteMessageList(IDList)
{
IDList = Array.isArray(IDList) ? IDList : [IDList];
$.ajax({
url:getAsJsonUrl + '&action=flagDeleted',
data:
{
token:token,
messageIds:IDList
},
type: "POST",
dataType: "json",
success:data =>
{
token = data.newAjaxToken;
if(data.status === 'failure')
{
showNotification(data.errors[0].message, 'error');
return;
}
},
error:data =>
{
showNotification(data.errors[0].message, 'error');
}
});
}
checkDialog()
{
if(serverTime.getTime() - this.dialogDelay < 500) return;
this.dialogDelay = serverTime.getTime();
const dialog = document.querySelector('.ui-dialog');
const id = dialog.querySelector('.detail_msg')?.getAttribute('data-msg-id');
const isCombat = dialog.querySelector('[data-combatreportid]');
const isSpy = dialog.querySelector('[data-message-type="10"]');
const actionDiv = dialog.querySelector('message-footer-actions');
if(id && isCombat && !dialog.querySelector('.ogl_messageButton'))
{
const apiButton = dialog.querySelector('.icon_apikey');
const api = (apiButton.getAttribute('data-tooltip-title') || apiButton.getAttribute('title') || apiButton.getAttribute('data-title') || apiButton.getAttribute('data-api-code')).match(/cr-[a-z0-9-]*/)[0];
apiButton.setAttribute('data-api-code', api);
Util.addDom('div',
{
class:'ogl_messageButton tooltip',
title:'Convert this battle',
parent:actionDiv,
child:'C',
onclick:() => window.open(Util.genConverterLink(this.ogl, api), '_blank')
});
}
else if(id && isSpy && !dialog.querySelector('.ogl_messageButton'))
{
const params = new URLSearchParams(dialog.querySelector('.msg_title a')?.href);
const coords = [params.get('galaxy') || "0", params.get('system') || "0", params.get('position') || "0"];
const apiButton = dialog.querySelector('.icon_apikey');
const api = (apiButton.getAttribute('data-tooltip-title') || apiButton.getAttribute('title') || apiButton.getAttribute('data-title') || apiButton.getAttribute('data-api-code')).match(/sr-[a-z0-9-]*/)[0];
apiButton.setAttribute('data-api-code', api);
if(!dialog.querySelector('.ogl_tagPicker'))
{
const colorButton = Util.addDom('div',
{
class:'ogl_messageButton',
parent:actionDiv
});
this.ogl._ui.addTagButton(colorButton, coords);
}
if(!dialog.querySelector('.ogl_trashsim'))
{
Util.addDom('div',
{
class:'ogl_messageButton material-icons ogl_trashsim tooltip',
parent:actionDiv,
child:'play_arrow',
onclick:() => window.open(Util.genTrashsimLink(this.ogl, api), '_blank')
});
}
if(!dialog.querySelector('.ogl_ptre') && this.ogl.ptreKey)
{
Util.addDom('div',
{
class:'ogl_messageButton material-icons tooltip',
parent:actionDiv,
child:'ptre',
onclick:() => this.ogl.PTRE.postSpyReport(api)
});
}
}
initTooltips();
}
checkBoard()
{
if(this.ogl.server.lang != 'fr' || !this.ogl.db.options.boardTab) return;
this.ogl.db.lastBoardPosts = this.ogl.db.lastBoardPosts || [0, 0, 0]; // count, last post, last check
if(Date.now() > this.ogl.db.lastBoardPosts[2] + 3600000) // 1h
{
GM_xmlhttpRequest(
{
method:'GET',
url:'https://board.fr.ogame.gameforge.com/index.php?board-feed/101/',
onload:result =>
{
const xml = new DOMParser().parseFromString(result.responseText, 'text/xml');
this.ogl.db.lastBoardPosts[0] = 0;
const initialLastPost = this.ogl.db.lastBoardPosts[1];
const items = xml.querySelectorAll('item');
items.forEach((item, index) =>
{
const date = new Date(item.querySelector('pubDate').textContent).getTime();
if(date > initialLastPost)
{
this.ogl.db.lastBoardPosts[0]++;
}
if(index == 0) this.ogl.db.lastBoardPosts[1] = date;
if(this.ogl.db.lastBoardPosts[0] > 0)
{
const count = document.querySelector('.comm_menu.messages .new_msg_count') || Util.addDom('span', { class:'new_msg_count totalMessages news' });
count.innerText = parseInt((count?.innerText || 0)) + this.ogl.db.lastBoardPosts[0];
}
this.ogl.db.lastBoardPosts[2] = Date.now();
});
}
});
}
}
addBoardTab()
{
if(this.ogl.server.lang != 'fr' || !this.ogl.db.options.boardTab) return;
const div = Util.addDom('div', { class:'ogl_boardMessageTab', parent:document.querySelector('.mainTabs') });
Util.addDom('div', { class:'tabImage', parent:div, child:Util.addDom('div', { class:'material-icons', child:'newspaper' }) });
Util.addDom('div', { class:'tabLabel', parent:div, child:'Board.fr' });
const newMessagesCount = Util.addDom('div', { class:'newMessagesCount ogl_hidden', parent:div, child:this.ogl.db.lastBoardPosts[0] });
if(this.ogl.db.lastBoardPosts[0] > 0) newMessagesCount.classList.remove('ogl_hidden');
div.addEventListener('click', () =>
{
const wrapper = document.querySelector('#messagewrapper');
wrapper.innerText = '';
const inner = Util.addDom('div', { id:'oglBoardTab', class:'messagesHolder', parent:wrapper, child:'<div class="ogl_wrapperloading"><div class="ogl_loading"></div></div>' });
document.querySelectorAll('.mainTabs .marker').forEach(e => e.classList.remove('marker'));
div.classList.add('marker');
GM_xmlhttpRequest(
{
method:'GET',
url:'https://board.fr.ogame.gameforge.com/index.php?board-feed/101/',
onload:result =>
{
const xml = new DOMParser().parseFromString(result.responseText, 'text/xml');
const items = xml.querySelectorAll('item');
inner.innerText = '';
items.forEach((item, index) =>
{
const rawDate = new Date(item.querySelector('pubDate').textContent);
const date = rawDate.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'});
const time = rawDate.toLocaleTimeString('de-DE');
const msg = Util.addDom('div', { class:'msg', parent:inner });
Util.addDom('span', { class:'msg_title blue_txt', parent:msg, child:`${item.querySelector('title').textContent}<br><i>@${item.getElementsByTagName('dc:creator')[0].textContent}</i>`, onclick:() =>
{
window.open(item.querySelector('link').textContent, '_blank');
}});
Util.addDom('span', { class:'msg_date fright ogl_CustomMessagedate', parent:msg, child:`${date} ${time}` });
Util.addDom('div', { class:'msg_content', parent:msg, child:item.getElementsByTagName('content:encoded')[0].textContent });
if(index == 0) this.ogl.db.lastBoardPosts[1] = rawDate.getTime();
});
this.ogl._time.updateList.push('.ogl_CustomMessagedate');
this.ogl.db.lastBoardPosts[0] = 0;
this.ogl.db.lastBoardPosts[2] = Date.now();
newMessagesCount.classList.add('ogl_hidden');
}
});
});
}
}
class MovementManager extends Manager
{
load(reload)
{
this.ogl.cache.movements = this.ogl.cache.movements || {};
this.destinationList = {};
// if eventFleets are already loaded, we still need to get data
if(document.querySelector('#eventboxContent .eventFleet'))
{
$.ajax({
url:eventlistLink,
success:function() {}
});
}
if(this.ogl.page == 'movement' && !reload)
{
unsafeWindow['timerHandler'].pageReloadAlreadyTriggered = true; // prevent auto reload
this.updateMovement();
}
}
addFleetIcon(data, planet, reversed)
{
Util.addDom('div', { class:`material-icons ogl_fleetIcon ogl_mission${data[0].mission} tooltip`, parent:reversed ? planet._ogl.sideIconBack : planet._ogl.sideIcon, 'data-list':data.length, onclick:() =>
{
const container = Util.addDom('div', { class:'ogl_sideFleetTooltip' });
let cumul = { metal:0, crystal:0, deut:0 };
data.forEach(line =>
{
const fleetImg = reversed ? 'https://gf2.geo.gfsrv.net/cdn47/014a5d88b102d4b47ab5146d4807c6.gif' : 'https://gf2.geo.gfsrv.net/cdnd9/f9cb590cdf265f499b0e2e5d91fc75.gif';
let shipAmount = 0;
Object.keys(line).filter(element => parseInt(element)).forEach(shipID => shipAmount += line[shipID]);
let tooltip = Util.addDom('table', { class:'fleetinfo ogl_custom', child:'' });
[...this.ogl.shipsList, 'metal', 'crystal', 'deut', 'food'].forEach(item =>
{
if(line[item] || isNaN(item)) tooltip.innerHTML += `<tr><td>${this.ogl._lang.find(item)}</td><td class="value">${line[item] || 0}</td></tr>`;
});
const domLine = Util.addDom('div', { class:`ogl_mission${line.mission} ogl_sideFleetIcon`, child:`<div class="ogl_icon ogl_mission${line.mission}"></div><div class="material-icons">${line.from.isMoon ? 'bedtime' : 'language'}</div><div>[${line.from.coords}]</div><span>${Util.formatToUnits(shipAmount)}</span><img class="tooltip" title='${tooltip.outerHTML}' src="${fleetImg}"><div class="material-icons">${line.mission == 8 ? 'debris' : line.to.isMoon ? 'bedtime' : 'language'}</div><div>[${line.to.coords}]</div>`, parent:container });
['metal', 'crystal', 'deut'].forEach(res =>
{
Util.addDom('div', { class:`ogl_icon ogl_${res}`, parent:domLine, child:Util.formatToUnits(line[res] || 0) });
cumul[res] = cumul[res] + (line[res] || 0);
});
// /!\ caution, line.arrivalTime is the client time (wtf gf)
const timeObj = this.ogl._time.getObj(line.arrivalTime, 'client');
const time = this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server;
domLine.prepend(this.ogl._time.convertTimestampToDate(time));
});
const total = Util.addDom('div', { class:`ogl_sideFleetIcon`, child:`<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>`, parent:container });
['metal', 'crystal', 'deut'].forEach(res => Util.addDom('div', { class:`ogl_icon ogl_${res}`, parent:total, child:Util.formatToUnits(cumul[res] || 0) }));
//const docked = Util.addDom('div', { class:`ogl_sideFleetIcon`, child:`<span></span><span></span><span></span><span></span><span></span><span></span><span>docked</span>`, parent:container });
//['metal', 'crystal', 'deut'].forEach(res => Util.addDom('div', { class:`ogl_icon ogl_${res}`, parent:docked, child:Util.formatToUnits(ogl.db.myPlanets?.[targetID]?.[res] || 0) }));
this.ogl._popup.open(container);
}});
}
updateMovement()
{
let emptyData = false;
if(document.querySelectorAll('#movementcomponent .reversal a').length > 0)
{
document.querySelectorAll('#movementcomponent .reversal a')[0].setAttribute('data-key-color', 'orange');
Array.from(document.querySelectorAll('#movementcomponent .reversal a')).sort((a, b) => parseInt(b.closest('.fleetDetails').getAttribute('id').replace('fleet', '')) - parseInt(a.closest('.fleetDetails').getAttribute('id').replace('fleet', '')))[0].setAttribute('data-key-color', 'violet');
}
document.querySelectorAll('.route a').forEach((route, index) =>
{
route.classList.add('tooltipRight');
const parent = route.closest('.fleetDetails');
const resourcesBlock = Util.addDom('div', { class:'ogl_resourcesBlock' });
const timeBlock = Util.addDom('div', { class:'ogl_timeBlock' });
const actionsBlock = Util.addDom('div', { class:'ogl_actionsBlock' });
const htmlData = document.querySelector(`#${route.getAttribute('rel')}`);
if(!htmlData)
{
emptyData = true;
return;
}
// get fleet compo
htmlData.querySelectorAll('.fleetinfo tr').forEach(subline =>
{
if(subline.querySelector('td') && subline.querySelector('.value'))
{
const name = subline.querySelector('td').innerText.replace(':', '');
const key = Object.entries(this.ogl.db.serverData).find(entry => entry[1] === name)[0];
const value = parseInt(subline.querySelector('.value').innerText.replace(/\.|,| /g, ''));
const formattedValue = Util.formatToUnits(value, 0);
if(!value) return;
if(!isNaN(key))
{
Util.addDom('div', { class:`ogl_icon ogl_${key}`, child:formattedValue, parent:resourcesBlock });
}
else
{
if(key == 'metal') Util.addDom('div', { class:`ogl_icon ogl_${key}`, child:formattedValue, prepend:resourcesBlock });
else if(key == 'crystal') Util.addDom('div', { class:`ogl_icon ogl_${key}`, child:formattedValue, after:resourcesBlock.querySelector('.ogl_metal') });
else if(key == 'deut') Util.addDom('div', { class:`ogl_icon ogl_${key}`, child:formattedValue, after:resourcesBlock.querySelector('.ogl_crystal') });
else if(key == 'food') Util.addDom('div', { class:`ogl_icon ogl_${key}`, child:formattedValue, after:resourcesBlock.querySelector('.ogl_deut') });
}
}
});
if(parent.getAttribute('data-mission-type') == 17 || parent.getAttribute('data-mission-type') == 18) // docks & discoveries
{
Util.addDom('div', { class:`ogl_icon ogl_metal`, child:0, prepend:resourcesBlock });
Util.addDom('div', { class:`ogl_icon ogl_crystal`, child:0, prepend:resourcesBlock });
Util.addDom('div', { class:`ogl_icon ogl_deut`, child:0, prepend:resourcesBlock });
Util.addDom('div', { class:`ogl_icon ogl_food`, child:0, prepend:resourcesBlock });
}
/*const fleetID = parent.id;
const arrival = parseInt(parent.dataset.arrivalTime) * 1000;
if(this.ogl.db.browserNotificationList[fleetID])
{
const browserNotification = {};
browserNotification.id = fleetID;
browserNotification.arrivalTime = arrival;
this.ogl.db.browserNotificationList[fleetID] = browserNotification;
}*/
/*Util.addDom('div', { parent:resourcesBlock, class:this.ogl.db.browserNotificationList[fleetID] ? 'ogl_clockNotif ogl_button ogl_active': 'ogl_clockNotif ogl_button', onclick:e =>
{
const browserNotification = {};
browserNotification.id = fleetID;
browserNotification.arrivalTime = arrival;
if(!this.ogl.db.browserNotificationList[fleetID])
{
this.ogl.db.browserNotificationList[fleetID] = browserNotification;
e.target.classList.add('ogl_active');
}
else
{
delete this.ogl.db.browserNotificationList[fleetID];
e.target.classList.remove('ogl_active');
}
console.log(this.ogl.db.browserNotificationList);
}});*/
const timeBlockLeft = Util.addDom('div', { class:'ogl_timeBlockLeft', parent:timeBlock });
const timeBlockRight = Util.addDom('div', { class:'ogl_timeBlockRight', parent:timeBlock });
timeBlockLeft.appendChild(parent.querySelector('.timer'));
timeBlockLeft.appendChild(parent.querySelector('.absTime'));
timeBlockLeft.appendChild(parent.querySelector('.originData'));
timeBlockLeft.querySelector('.originData').appendChild(timeBlockLeft.querySelector('.originCoords'));
timeBlockRight.appendChild(parent.querySelector('.destinationData'));
timeBlockRight.querySelector('.destinationData').appendChild(timeBlockRight.querySelector('.destinationPlanet'));
if(parent.querySelector('.nextabsTime')) timeBlockRight.appendChild(parent.querySelector('.nextabsTime'));
else Util.addDom('div', { child:'-', parent:timeBlockRight });
if(parent.querySelector('.nextTimer')) timeBlockRight.appendChild(parent.querySelector('.nextTimer'));
else Util.addDom('div', { child:'-', parent:timeBlockRight });
Util.addDom('div', { class:`ogl_icon ogl_mission${parent.getAttribute('data-mission-type')}`, prepend:actionsBlock });
actionsBlock.appendChild(parent.querySelector('.route a'));
//if(parent.querySelector('.openDetails')) actionsBlock.appendChild(parent.querySelector('.openDetails'));
if(parent.querySelector('.fedAttack')) actionsBlock.appendChild(parent.querySelector('.fedAttack'));
if(parent.querySelector('.sendMail')) actionsBlock.appendChild(parent.querySelector('.sendMail'));
parent.prepend(resourcesBlock);
parent.prepend(timeBlock);
parent.prepend(actionsBlock);
});
if(!emptyData) this.ogl._time.updateMovements();
}
check(xml)
{
let movements = {};
let ignored = [];
xml.querySelectorAll('#eventContent tbody tr').forEach(line =>
{
const tooltip = Util.addDom('div', {child:(line.querySelector('.icon_movement .tooltip') || line.querySelector('.icon_movement_reserve .tooltip'))?.getAttribute('title')});
const movement = {};
movement.id = parseInt(line.getAttribute('id').replace('eventRow-', ''));
movement.mission = line.getAttribute('data-mission-type');
movement.isBack = line.getAttribute('data-return-flight') === 'true';
movement.arrivalTime = parseInt(line.getAttribute('data-arrival-time')) * 1000;
if(!movement.isBack) ignored.push(movement.id + 1);
movement.from = {};
movement.from.anotherPlayer = !Boolean(Array.from(document.querySelectorAll('#planetList .planet-koords')).find(p => p.innerText === line.querySelector('.coordsOrigin').innerText.trim().slice(1, -1)));
movement.from.isMoon = Boolean(line.querySelector('.originFleet figure.moon'));
movement.from.coords = line.querySelector('.coordsOrigin').innerText.trim().slice(1, -1);
movement.to = {};
movement.to.anotherPlayer = !Boolean(Array.from(document.querySelectorAll('#planetList .planet-koords')).find(p => p.innerText === line.querySelector('.destCoords').innerText.trim().slice(1, -1)));
movement.to.isMoon = Boolean(line.querySelector('.destFleet figure.moon'));
movement.to.coords = line.querySelector('.destCoords').innerText.trim().slice(1, -1);
const fleetID = `fleetEvent-${movement.id}`;
const timeObj = this.ogl._time.getObj(movement.arrivalTime, 'client');
const arrival = timeObj.server;
const parent = document.querySelector(`#eventRow-${movement.id}`);
if(parent)
{
this.ogl._time.update(parent.querySelector('arrivalTime'));
const notifIcon = Util.addDom('div', { parent:parent, class:this.ogl.db.browserNotificationList[fleetID] ? 'ogl_clockNotif ogl_button ogl_active': 'ogl_clockNotif ogl_button', onclick:e =>
{
const browserNotification = {};
browserNotification.id = fleetID;
browserNotification.arrivalTime = arrival;
browserNotification.message = `[${movement.to.coords}] ${movement.to.isMoon ? 'moon' : 'planet'} : Your fleet is ready`;
this.ogl._notification.addNotification(browserNotification, e.target);
}});
if(this.ogl.db.browserNotificationList[fleetID] && Math.abs(this.ogl.db.browserNotificationList[fleetID].arrivalTime - arrival) > 5000)
{
notifIcon.classList.add('ogl_altered');
}
}
if(ignored.indexOf(movement.id) > -1) return;
this.destinationList[movement.to.coords] = this.destinationList[movement.to.coords] || [];
if(!movement.isBack && this.destinationList[movement.to.coords].indexOf(movement.mission) < 0) this.destinationList[movement.to.coords].push(movement.mission);
if((movement.mission == 1 || movement.mission == 6 || movement.mission == 9) && movement.from.anotherPlayer)
{
const dest = Array.from(document.querySelectorAll('#planetList .planet-koords')).find(p => p.innerText === line.querySelector('.destCoords').innerText.trim().slice(1, -1));
if(dest)
{
const destSmallPlanet = dest.closest('.smallplanet');
const destTarget = movement.to.isMoon ? destSmallPlanet.querySelector('.moonlink') : destSmallPlanet.querySelector('.planetlink');
destTarget.classList.add('ogl_attacked');
}
}
tooltip.querySelectorAll('.fleetinfo tr').forEach(subline =>
{
if(subline.querySelector('td') && subline.querySelector('.value'))
{
let name = subline.querySelector('td').innerText.replace(':', '');
let key = Object.entries(this.ogl.db.serverData).find(entry => entry[1] === name)?.[0];
let value = subline.querySelector('.value').innerText.replace(/\.|,| /g, '');
if(key) movement[key] = Number(value);
}
});
let target;
if(movement.isBack) target = movement.from.coords + ':B';
else if(movement.to.anotherPlayer) target = movement.from.coords;
else if(movement.from.anotherPlayer) target = movement.to.coords + ':B';
else target = movement.to.coords;
if(target)
{
movements[target] = movements[target] || [];
movements[target].push(movement);
}
});
this.ogl.cache.movements = movements;
this.updateSideIcons();
Util.runAsync(() =>
{
this.ogl._ui.displayResourcesRecap();
this.ogl._time.updateMovements(); // /!\ time.updateMovements != this.updateMovements
this.updateDebrisIndicators();
initTooltips();
});
}
updateSideIcons()
{
Object.values(this.ogl._dom.planet).filter(e => e._ogl.type == 'planet').forEach(planet =>
{
planet.parentNode.querySelectorAll('.ogl_fleetIcon').forEach(e => e.remove());
const coords = planet._ogl.coords;
if(this.ogl.cache?.movements?.[coords])
{
this.addFleetIcon(this.ogl.cache.movements[coords], planet);
}
if(this.ogl.cache?.movements?.[coords+':B'])
{
this.addFleetIcon(this.ogl.cache.movements[coords+':B'], planet, true);
}
});
if(this.ogl._tech) this.ogl._tech.checkTodolist();
}
updateDebrisIndicators()
{
for(let [coords, missionList] of Object.entries(this.destinationList))
{
if(missionList.indexOf('8') >= 0)
{
document.querySelectorAll(`[data-debris-coords="${coords}"]`).forEach(element =>
{
element.classList.add('ogl_attacked');
});
}
}
}
}
class HighscoreManager extends Manager
{
load()
{
/*this.ogl.db.lastStatusUpdate = this.ogl.db.lastStatusUpdate || 0;
this.ogl.db.lastGlobalScoreUpdate = this.ogl.db.lastGlobalScoreUpdate || 0;*/
this.rankingDBName = `${this.ogl.DBName}-highscore`;
this.ogl.db.lastPTREAPIUpdate = this.ogl.db.lastPTREAPIUpdate || 0;
this.tagToNameList =
{
n:'status_abbr_active',
v:'status_abbr_vacation',
I:'status_abbr_longinactive',
i:'status_abbr_inactive',
b:'status_abbr_banned',
a:'status_abbr_admin',
HONORABLE:'status_abbr_honorableTarget',
}
this.nameToTagList = Object.fromEntries(Object.entries(this.tagToNameList).map(e => e.reverse()));
this.nameToServerTagList =
{
'status_abbr_inactive' : this.ogl.db.serverData.inactive,
'status_abbr_longinactive' : this.ogl.db.serverData.inactiveLong,
'status_abbr_banned' : this.ogl.db.serverData.banned,
'status_abbr_vacation' : this.ogl.db.serverData.vacation,
'status_abbr_active' : false,
'status_abbr_honorableTarget' : 'HONORABLE', // as it is relative to the difference between two players, this status doesn't exist in ogame API
}
this.turnApiStatusToName = status =>
{
if(status.indexOf('v') > -1) status = 'status_abbr_vacation';
else if(status.indexOf('I') > -1) status = 'status_abbr_longinactive';
else if(status.indexOf('i') > -1) status = 'status_abbr_inactive';
else if(status.indexOf('b') > -1) status = 'status_abbr_banned';
else status = 'status_abbr_active';
return status;
}
if(this.ogl.page == 'highscore')
{
setTimeout(() => this.check());
}
}
check()
{
if(serverTime.getTime() - this.ogl.db.lastPTREAPIUpdate > 86400000 / 4) // 6h
{
this.ogl.PTRE.getRank({},
data =>
{
if(data?.code == 1)
{
GM_setValue(this.rankingDBName, JSON.stringify(data));
this.ogl.db.lastPTREAPIUpdate = serverTime.getTime(); // (data?.ranks_array?.[0].timestamp || 0) * 1000;
//console.log(data)
}
this.loadData();
});
}
else this.loadData();
}
loadData()
{
const typesList = { 0:'global', 1:'economy', 2:'research', 3:'military', 8:'lifeform' };
if(currentCategory !== 1 || !typesList[currentType]) return;
document.querySelector('#stat_list_content').setAttribute('data-category', currentCategory);
document.querySelector('#stat_list_content').setAttribute('data-type', currentType);
const data = JSON.parse(GM_getValue(this.rankingDBName) || '{}');
const ts = data?.ranks_array?.[0]?.timestamp;
if(ts)
{
const hours = Math.floor(Math.abs(serverTime.getTime() - (parseInt(ts) * 1000)) / 36e5);
document.querySelector('#ranks td.score').innerText += ` (Δ ${hours}${LocalizationStrings.timeunits.short.hour})`;
}
document.querySelectorAll('#ranks tbody tr').forEach(line =>
{
const id = parseInt(line.getAttribute('id').replace(/\D/g, ''));
const domPlayerName = line.querySelector('.playername');
const ranking = parseInt(line.querySelector('.position').innerText.replace(/\D/g, '')) || parseInt(line.querySelector('.highscorePositionIcon')?.className?.replace(/\D/g, ''));
const name = domPlayerName.innerText.indexOf('...') > -1 && this.ogl.db.udb[id]?.name ? this.ogl.db.udb[id]?.name : domPlayerName.innerText.trim();
const score = line.querySelector('.score');
const currentScore = parseInt(score.innerText.replace(/\D/g, ''));
const oldData = data?.ranks_array?.find(e => e.player_id == id);
const statusClass = domPlayerName.className?.match(/\b(status_abbr\S*)/)?.[1] || null;
//const lastData = data.ranks_array_last.find(e => e.player_id == id);
if(id == this.ogl.account.id)
{
this.ogl.db.udb[id] = this.ogl.db.udb[id] || this.ogl.createPlayer(id);
const defaults =
{
global: 0,
economy: 0,
research: 0,
lifeform: 0,
military: 0,
globalRanking: 0,
economyRanking: 0,
researchRanking: 0,
lifeformRanking: 0,
militaryRanking: 0,
}
this.ogl.db.udb[id].score = Object.assign({}, defaults, this.ogl.db.udb[id].score);
}
if(currentType == 0 && ranking == 1) // update top 1 score for expeditions
{
this.ogl.db.serverData.topScore = currentScore;
}
if(oldData && currentType == 0)
{
const scoreDiff = currentScore - parseInt(oldData?.total_score || '0');
//const ratio = ((scoreDiff / currentScore) * 100).toFixed(2);
const div = Util.addDom('div', { class:'ogl_oldScore', child:`<em>${Util.formatNumber(new Intl.NumberFormat("de-DE", { signDisplay: "exceptZero" }).format(scoreDiff))}</em>`, parent:score });
if(scoreDiff > 0)
{
div.classList.add('ogl_ok');
}
else if(scoreDiff < 0)
{
div.classList.add('ogl_danger');
}
}
domPlayerName.innerText = name;
if(this.ogl.db.udb[id]?.score?.[typesList[currentType]] != null) this.ogl.db.udb[id].score[typesList[currentType]] = currentScore;
if(this.ogl.db.udb[id]?.score?.[typesList[currentType]+'Ranking'] != null) this.ogl.db.udb[id].score[typesList[currentType]+'Ranking'] = ranking;
if(this.ogl.db.udb[id] && name.indexOf('...') < 0) this.ogl.db.udb[id].name = name;
let status = '';
if(this.ogl.db.udb[id] && (this.ogl.db.udb[id].status == 'v' || this.ogl.db.udb[id].status == 'o' || this.ogl.db.udb[id].status == 'd' || !statusClass))
{
status = this.ogl.db.udb[id].status || 'I';
}
else
{
status = this.ogl.playerStatus.find(e => e.class == statusClass)?.defaultTag || 'n';
}
if(this.ogl.db.udb[id]) this.ogl.db.udb[id].status = status;
/*if(this.ogl.db.udb[id] && oldData && (this.ogl.db.udb[id]?.liveUpdate || 0) < oldData.timestamp * 1000) // update player status
{
this.ogl.db.udb[id].status = this.ogl.playerStatus.find(e => e.class == statusClass || e.class == this.turnApiStatusToName(oldData.status))?.defaultTag || 'n';
status = this.ogl.db.udb[id].status;
}
else if(this.ogl.db.udb[id]) // get status from OGL player db
{
status = this.ogl.db.udb[id].status;
}
else if(oldData?.status) // get status from last api update
{
status = this.ogl.playerStatus.find(e => e.defaultTag == oldData.status)?.defaultTag || statusClass;
}
else status = 'n';*/
if(!line.querySelector('.ogl_flagPicker'))
{
this.ogl._ui.turnIntoPlayerLink(id, domPlayerName, false, status);
this.ogl._ui.addPinButton(line.querySelector('.highscoreNameFieldWrapper'), id);
}
});
initTooltips();
}
}
class ShortcutManager extends Manager
{
load()
{
document.querySelector('.ogl_shortcuts')?.remove();
document.querySelector('.ogl_shortCutWrapper')?.remove();
this.keyList = {};
this.shortCutWrapper = Util.addDom('div', { class:'ogl_shortCutWrapper', child:'<div></div>' });
this.shortcutDiv = Util.addDom('div', { class:'ogl_shortcuts', parent:this.ogl.db.options.shortcutsOnRight ? document.querySelector('#rechts') : this.shortCutWrapper });
this.locked = false;
this.lastExecution = 0;
if(!this.loaded)
{
document.addEventListener('keydown', event =>
{
let activeElement = document.activeElement;
const tooltipVisible = document.querySelector('.tippy-box[data-state="visible"]');
const tooltipValidationButton = document.querySelector('.tippy-box .ogl_formValidation');
const popupVisible = document.querySelector('.ogl_popup.ogl_active');
const inputFocused = activeElement.tagName == 'INPUT' || activeElement.tagName == 'TEXTAREA';
if(!event.repeat)
{
if(event.key.toLowerCase() == 'enter' && tooltipVisible && tooltipValidationButton)
{
tooltipValidationButton.click();
return;
}
else if(event.key.toLowerCase() == 'escape' && popupVisible && !inputFocused)
{
this.ogl._popup.close();
return;
}
}
if(!inputFocused && this.keyList[event.key.toLowerCase()] && !this.locked && !event.ctrlKey && !event.shiftKey) // can use !event.repeat instead of this.locked
{
this.locked = true;
this.keyList[event.key.toLowerCase()]();
}
else if(!inputFocused && !isNaN(event.key) && this.keyList['2-9'] && !this.locked && !event.ctrlKey && !event.shiftKey) // can use !event.repeat instead of this.locked
{
this.locked = true;
this.keyList['2-9'](event.key);
}
}, { capture: true });
document.addEventListener('keyup', () => this.locked = false);
visualViewport.addEventListener('resize', () => this.updateShortcutsPosition());
visualViewport.addEventListener('scroll', () => this.updateShortcutsPosition());
}
this.loaded = true;
this.add('menu', () =>
{
if(document.querySelector('.ogl_side.ogl_active .ogl_config'))
{
this.ogl._ui.side.classList.remove('ogl_active');
delete this.ogl.db.currentSide;
}
else this.ogl._topbar.openSettings();
return false;
});
this.add('showMenuResources', () =>
{
this.ogl.db.options.showMenuResources++;
if(this.ogl.db.options.showMenuResources > 2) this.ogl.db.options.showMenuResources = 0;
localStorage.setItem('ogl_menulayout', this.ogl.db.options.showMenuResources);
document.body.setAttribute('data-menulayout', this.ogl.db.options.showMenuResources);
return false;
});
this.add('previousPlanet', () =>
{
localStorage.setItem('ogl-redirect', false);
document.body.classList.remove('ogl_destinationPicker');
this.redirectToPlanet(-1);
});
this.add('nextPlanet', () =>
{
localStorage.setItem('ogl-redirect', false);
document.body.classList.remove('ogl_destinationPicker');
this.redirectToPlanet(1);
});
if((!isNaN(this.ogl.db.currentSide) || this.ogl.db.currentSide == "tagged") && document.querySelector('.ogl_side.ogl_active'))
{
this.add('nextPinnedPosition', () =>
{
if(!isNaN(this.ogl.db.currentSide) && document.querySelector('.ogl_side.ogl_active'))
{
const arr = Array.from(document.querySelectorAll('.ogl_pinDetail [data-galaxy]'));
const index = arr.findLastIndex(e => e.classList.contains('ogl_active'));
const target = Util.reorderArray(arr, index)[1];
if(target) target.click();
}
else if(this.ogl.db.currentSide == "tagged" && document.querySelector('.ogl_side.ogl_active'))
{
const arr = Array.from(document.querySelectorAll('.ogl_tagged [data-galaxy]'));
const index = arr.findLastIndex(e => e.classList.contains('ogl_active'));
const target = Util.reorderArray(arr, index)[1];
if(target) target.click();
}
else
{
fadeBox(this.ogl._lang.find('noCurrentPin'), true);
}
return false;
});
}
if(this.ogl.page == 'fleetdispatch')
{
Util.addDom('div', {class:'ogl_separator', parent:this.shortcutDiv});
this.add('expeditionSC', () => { if(fleetDispatcher.currentPage == 'fleet1') this.ogl._fleet.selectExpedition(202) }, 'fleet');
this.add('expeditionLC', () => { if(fleetDispatcher.currentPage == 'fleet1') this.ogl._fleet.selectExpedition(203) }, 'fleet');
this.add('expeditionPF', () => { if(fleetDispatcher.currentPage == 'fleet1') this.ogl._fleet.selectExpedition(219) }, 'fleet');
this.add('fleetRepeat', () =>
{
if(!this.ogl._fleet.isReady) return false;
if(fleetDispatcher.currentPage == 'fleet1')
{
fleetDispatcher.resetShips();
Object.values(this.ogl.db.previousFleet.shipsToSend).forEach(ship => fleetDispatcher.selectShip(ship.id, ship.number));
}
this.ogl._fleet.setRealTarget(fleetDispatcher.realTarget,
{
galaxy:this.ogl.db.previousFleet.targetPlanet.galaxy,
system:this.ogl.db.previousFleet.targetPlanet.system,
position:this.ogl.db.previousFleet.targetPlanet.position,
type:this.ogl.db.previousFleet.targetPlanet.type,
name:this.ogl.db.previousFleet.targetPlanet.name
});
fleetDispatcher.selectMission(this.ogl.db.previousFleet.mission);
fleetDispatcher.cargoMetal = this.ogl.db.previousFleet.cargoMetal;
fleetDispatcher.cargoCrystal = this.ogl.db.previousFleet.cargoCrystal;
fleetDispatcher.cargoDeuterium = this.ogl.db.previousFleet.cargoDeuterium;
fleetDispatcher.realSpeedPercent = this.ogl.db.previousFleet.speedPercent;
fleetDispatcher.speedPercent = this.ogl.db.previousFleet.speedPercent;
if(fleetDispatcher.currentPage == 'fleet2')
{
fleetDispatcher.fetchTargetPlayerData();
}
if(fleetDispatcher.mission == 15)
{
document.querySelector('#fleet2 #expeditiontime').value = this.ogl.db.previousFleet.expeditionTime;
document.querySelector('#fleet2 #expeditiontimeline .dropdown a').innerText = this.ogl.db.previousFleet.expeditionTime;
fleetDispatcher.updateExpeditionTime();
}
fleetDispatcher.setFleetPercent(fleetDispatcher.realSpeedPercent);
Object.values(document.querySelector('#speedPercentage'))[0].percentageBarInstance.setValue(fleetDispatcher.realSpeedPercent);
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
}, 'fleet');
this.add('fleetSelectAll', () =>
{
if(!this.ogl._fleet.isReady) return false;
if(fleetDispatcher.currentPage == 'fleet1') fleetDispatcher.selectAllShips();
else if(fleetDispatcher.currentPage == 'fleet2') fleetDispatcher.selectMaxAll();
fleetDispatcher.refresh();
}, 'fleet');
if(this.ogl.db.quickRaidList && this.ogl.db.quickRaidList.length > 0)
{
this.add('quickRaid', () =>
{
if(!this.ogl._fleet.isReady) return false;
if(fleetDispatcher.currentPage == 'fleet1')
{
fleetDispatcher.resetShips();
this.ogl._fleet.isQuickRaid = true;
const target = this.ogl.db.quickRaidList[0].match(/.{1,3}/g).map(Number);
const amount = this.ogl._fleet.shipsForResources(this.ogl.db.options.defaultShip, this.ogl.db.options.resourceTreshold);
fleetDispatcher.selectShip(this.ogl.db.options.defaultShip, amount);
fleetDispatcher.realTarget.galaxy = target[0];
fleetDispatcher.realTarget.system = target[1];
fleetDispatcher.realTarget.position = target[2];
fleetDispatcher.realTarget.type = 1;
fleetDispatcher.selectMission(1);
fleetDispatcher.targetPlanet.name = `Quick raid ${target.join(':')}`;
fleetDispatcher.cargoMetal = 0;
fleetDispatcher.cargoCrystal = 0;
fleetDispatcher.cargoDeuterium = 0;
fleetDispatcher.mission = 1;
fleetDispatcher.speedPercent = 10;
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
}
}, 'fleet');
}
this.add('fleetReverseAll', () =>
{
if(!this.ogl._fleet.isReady) return false;
if(fleetDispatcher.currentPage == 'fleet1')
{
fleetDispatcher.shipsOnPlanet.forEach(ship =>
{
const delta = ship.number - (fleetDispatcher.findShip(ship.id)?.number || 0);
fleetDispatcher.selectShip(ship.id, delta);
fleetDispatcher.refresh();
});
fleetDispatcher.refresh();
fleetDispatcher.focusSubmitFleet1();
}
else if(fleetDispatcher.currentPage == 'fleet2')
{
['metal', 'crystal', 'deut', 'food'].forEach(type =>
{
fleetDispatcher[this.ogl._fleet.cargo[type]] = Math.min(fleetDispatcher[this.ogl._fleet.resOnPlanet[type]] - fleetDispatcher[this.ogl._fleet.cargo[type]], fleetDispatcher.getFreeCargoSpace());
});
fleetDispatcher.refresh();
}
}, 'fleet');
this.add('fleetResourcesSplit', keyNumber =>
{
if(!this.ogl._fleet.isReady) return false;
this.keyNumberClickFleet1 = this.keyNumberClickFleet1 || 0;
this.keyNumberClickFleet2 = this.keyNumberClickFleet2 || 0;
if(fleetDispatcher.currentPage == 'fleet1')
{
if(!keyNumber || isNaN(keyNumber)) keyNumber = 2 + this.keyNumberClickFleet1;
this.keyNumberClickFleet2 = this.keyNumberClickFleet1;
this.keyNumberClickFleet1++;
if(this.keyNumberClickFleet1 > 7) this.keyNumberClickFleet1 = 0;
if(keyNumber == 0) fleetDispatcher.resetShips();
else fleetDispatcher.shipsOnPlanet.forEach(ship => fleetDispatcher.selectShip(ship.id, Math.ceil(ship.number / keyNumber)));
}
else if(fleetDispatcher.currentPage == 'fleet2')
{
if(!keyNumber || isNaN(keyNumber)) keyNumber = 2 + this.keyNumberClickFleet2;
this.keyNumberClickFleet2++;
if(this.keyNumberClickFleet2 > 7) this.keyNumberClickFleet2 = 0;
fleetDispatcher.resetCargo();
let fleetDispatcherResources = ['metalOnPlanet', 'crystalOnPlanet', 'deuteriumOnPlanet'];
if(keyNumber == 0) fleetDispatcher.resetCargo();
else
{
document.querySelectorAll('#fleet2 #resources .res_wrap').forEach((resource, index) =>
{
let cargoType = ['cargoMetal', 'cargoCrystal', 'cargoDeuterium'];
let currentMax = fleetDispatcher[fleetDispatcherResources[index]];
if(index == 2) currentMax -= fleetDispatcher.getConsumption();
currentMax = Math.min(currentMax / keyNumber, fleetDispatcher.getFreeCargoSpace());
fleetDispatcher[cargoType[index]] = Math.max(Math.ceil(currentMax), 0);
resource.querySelector('input').value = fleetDispatcher[cargoType[index]];
//fleetDispatcher.focusSendFleet();
});
}
}
fleetDispatcher.refresh();
});
this.add('fleetQuickCollect', () =>
{
if(!this.ogl._fleet.isReady) return false;
document.querySelector(`.ogl_requiredShips .ogl_${this.ogl.db.options.defaultShip}`)?.click();
});
Util.addDom('div', { class:'ogl_shortcut ogl_button', 'data-key':'enter', child:'<span class="material-icons">subdirectory_arrow_left</span>', parent:this.shortcutDiv, onclick:() =>
{
if(!this.ogl._fleet.isReady) return false;
document.querySelector('#fleetdispatchcomponent').dispatchEvent(new KeyboardEvent('keypress', { keyCode:13 }));
}});
}
else if(this.ogl.page == 'messages')
{
Util.addDom('div', {class:'ogl_separator', parent:this.shortcutDiv});
this.add('enter', () =>
{
if(this.ogl._message.nextTarget)
{
document.querySelector(`.ogl_spyLine[data-id="${this.ogl._message.nextTarget.id}"] .ogl_loot`).click();
}
});
}
else if(this.ogl.page == 'galaxy')
{
Util.addDom('div', {class:'ogl_separator', parent:this.shortcutDiv});
this.add('galaxyUp', () => { submitOnKey('ArrowUp');return false; });
this.add('galaxyLeft', () => { submitOnKey('ArrowLeft');return false; });
this.add('galaxyDown', () => { submitOnKey('ArrowDown');return false; });
this.add('galaxyRight', () => { submitOnKey('ArrowRight');return false; });
this.add('galaxyReload', () => { submitForm();return false; });
this.add('galaxySpySystem', () => { document.querySelector('.spysystemlink').click();return false; });
this.add('discovery', () => sendSystemDiscoveryMission());
}
else if(this.ogl.page == 'movement')
{
Util.addDom('div', {class:'ogl_separator', parent:this.shortcutDiv});
this.add('backFirstFleet', () =>
{
document.querySelector('#movementcomponent .reversal a[data-key-color="orange"]') && document.querySelector('#movementcomponent .reversal a[data-key-color="orange"]').click();
}, false, 'orange');
this.add('backLastFleet', () =>
{
document.querySelector('#movementcomponent .reversal a[data-key-color="violet"]') && document.querySelector('#movementcomponent .reversal a[data-key-color="violet"]').click();
}, false, 'violet');
}
if(!this.ogl.db.options.shortcutsOnRight) document.body.appendChild(this.shortCutWrapper);
this.updateShortcutsPosition();
}
add(id, callback, type, color)
{
let key = this.ogl.db.options.keyboardActions[id];
if(id == 'enter')
{
key = id;
id = 'attackNext';
}
const callBackWithMessage = params =>
{
const result = callback(params);
if(result !== false) this.ogl._notification.addToQueue(this.ogl._lang.find(id));
}
const btn = Util.addDom('div',
{
'data-key':key,
'data-key-color':color,
'data-key-id':id,
class:'ogl_shortcut ogl_button tooltip',
parent:this.shortcutDiv,
title:this.ogl._lang.find(id),
child:key.replace('enter', '<span class="material-icons">subdirectory_arrow_left</span>'),
onclick:() => callBackWithMessage()
});
if(id == 'quickRaid') btn.innerText += ` (${this.ogl.db.quickRaidList.length})`;
this.keyList[key] = params =>
{
if(type == 'fleet' && (!this.ogl._fleet.isReady || !unsafeWindow.fleetDispatcher || unsafeWindow.fleetDispatcher.fetchTargetPlayerDataTimeout)) return;
callBackWithMessage(params);
};
}
updateShortcutsPosition()
{
if(this.ogl.db.options.shortcutsOnRight) return;
const div = this.shortCutWrapper;
div.style.top = visualViewport.offsetTop + 'px';
div.style.height = visualViewport.height - 25 / window.visualViewport.scale + 'px';
div.style.left = visualViewport.offsetLeft + 'px';
div.style.width = visualViewport.width + 'px';
this.shortcutDiv.style.gridGap = 7 / window.visualViewport.scale + 'px';
div.querySelectorAll('.ogl_shortcut').forEach(e => e.style.zoom = 1 / visualViewport.scale);
}
redirectToPlanet(direction)
{
const url = new URLSearchParams(window.location.search);
let urlParams = {};
urlParams.page = url.get('page');
urlParams.component = url.get('component');
urlParams.ogldestinationtype = url.get('ogldestinationtype');
urlParams.ogldestinationid = url.get('ogldestinationid');
urlParams.oglfirstsourceid = url.get('oglfirstsourceid');
urlParams.galaxy = url.get('galaxy');
urlParams.system = url.get('system');
urlParams.position = url.get('position');
urlParams.type = url.get('type');
const currentPlanet = this.ogl.account.planets.getCurrent();
const destination = urlParams.destination || currentPlanet.currentType;
let nextPlanet = this.ogl.account.planets.getNext();
let nextPlanetWithMoon = this.ogl.account.planets.getNextWithMoon();
let prevPlanet = this.ogl.account.planets.getPrev();
let prevPlanetWithMoon = this.ogl.account.planets.getPrevWithMoon();
if(urlParams.ogldestinationid == nextPlanet.id) nextPlanet = this.ogl.account.planets.getNext(1);
if(urlParams.ogldestinationid == nextPlanetWithMoon.moonID) nextPlanetWithMoon = this.ogl.account.planets.getNextWithMoon(1);
if(urlParams.ogldestinationid == prevPlanet.id) prevPlanet = this.ogl.account.planets.getPrev(1);
if(urlParams.ogldestinationid == prevPlanetWithMoon.moonID) prevPlanetWithMoon = this.ogl.account.planets.getPrevWithMoon(1);
const params = {};
params.page = urlParams.page;
if(urlParams.component) params.component = urlParams.component;
params.cp = direction == 1 ? (destination == 'moon' ? nextPlanetWithMoon.moonID : nextPlanet.id) : (destination == 'moon' ? prevPlanetWithMoon.moonID : prevPlanet.id);
if(direction === 0) delete params.cp;
if(this.ogl.mode) params.oglmode = this.ogl.mode;
if(urlParams.ogldestinationtype) params.ogldestinationtype = urlParams.ogldestinationtype;
for(let [key, value] of Object.entries(urlParams))
{
if(value) params[key] = value;
}
if(direction !== 0 && this.ogl.mode && (urlParams.oglfirstsourceid == nextPlanet.id || urlParams.oglfirstsourceid == nextPlanetWithMoon.moonID))
{
window.location.href = this.getRedirectionLink({ component:'overview', cp:params.cp });
}
else
{
window.location.href = this.getRedirectionLink(params);
}
}
getRedirectionLink(params)
{
params = params || {};
params.page = params.page || 'ingame';
let link = `https://${window.location.host}/game/index.php?page=${params.page}`;
for(let [key, value] of Object.entries(params))
{
if(key != 'page') link += `&${key}=${value}`;
}
return link;
}
}
class TechManager extends Manager
{
load()
{
this.ogl.currentPlanet.obj.todolist = this.ogl.currentPlanet.obj.todolist || {};
this.initialLevel = 0;
this.levelOffset = 0;
this.detailCumul = {};
this.checkProductionBoxes();
this.ogl._movement.updateSideIcons();
if(unsafeWindow['technologyDetails'])
{
document.querySelectorAll('#technologydetails').forEach((e, index) => { if(index > 0) e.remove(); });
technologyDetails.show = technologyId =>
{
if(this.xhr)
{
this.xhr.abort();
}
const wrapper = document.querySelector('#technologydetails_wrapper');
const content = wrapper.querySelector('#technologydetails_content');
document.querySelectorAll('.technology.showsDetails').forEach(e => e.classList.remove('showsDetails'));
if(!content.querySelector('.ogl_loading'))
{
content.innerHTML = '<div class="ogl_wrapperloading"><div class="ogl_loading"></div></div>';
}
wrapper.classList.add('ogl_active');
const getData = tries =>
{
tries = tries || 0;
this.xhr = $.ajax(
{
url:technologyDetails.technologyDetailsEndpoint,
data: { technology:technologyId }
})
.done(data =>
{
try
{
const json = JSON.parse(data);
if(json.status === 'failure') technologyDetails.displayErrors(json.errors);
else
{
$('#technologydetails_content').html(json.content[json.target]);
this.check(technologyId, wrapper);
}
}
catch(error)
{
if(tries < 2) setTimeout(() => getData(tries + 1), 1000);
}
});
}
getData();
}
technologyDetails.hide = () =>
{
const wrapper = document.querySelector('#technologydetails_wrapper');
wrapper.classList.remove('ogl_active');
wrapper.classList.remove('slide-up');
document.querySelectorAll('.technology.showsDetails').forEach(e => e.classList.remove('showsDetails'));
technologyDetails.id = false;
technologyDetails.lvl = false;
}
const urlTech = new URLSearchParams(window.location.search).get('openTech');
if(urlTech) technologyDetails.show(urlTech);
}
document.querySelectorAll('#technologies .technology[data-technology]').forEach(tech =>
{
const id = tech.getAttribute('data-technology');
this.ogl.db.serverData[id] = tech.getAttribute('aria-label') || id;
if(id == 217)
{
const amount = this.calcMaxCrawler();
const crawlerInfo = Util.addDom('div', { class:'ogl_crawlerInfo' });
Object.entries(amount).forEach(entry =>
{
Util.addDom('div', { parent:crawlerInfo, child:`${entry[0]}%<i class="material-icons">arrow_forward</i>${Util.formatNumber(entry[1])}` });
});
tech.appendChild(crawlerInfo);
}
if(this.ogl.db.options.debugMode)
{
Util.addDom('div', { style:'background:rgba(0,0,0,.8); position:relative; top:20px; text-align:center;', child:`#${id}`, parent:tech.querySelector('.icon') });
}
});
this.ogl._topbar.checkUpgrade();
Util.overWrite('reload_page', unsafeWindow, url =>
{
this.ogl.db.noFetch = true;
});
}
check(id, details)
{
if(details.querySelector('.shipyardSelection'))
{
details.querySelector('.sprite_large').appendChild(details.querySelector('.shipyardSelection'));
}
const actions = Util.addDom('div', { parent:details.querySelector('.sprite') || details.querySelector('.sprite_large'), class:'ogl_actions' });
const data = Datafinder.getTech(id);
this.levelOffset = 0;
this.initialLevel = parseInt(details.querySelector('.information .level')?.getAttribute('data-value') || 0);
let amount = details.querySelector('#build_amount');
if(document.querySelector(`#technologies .technology[data-technology="${id}"] .targetlevel`)?.getAttribute('data-value') >= this.initialLevel)
{
this.initialLevel += 1;
}
if(!amount)
{
if(id != 407 && id != 408) // defense shieds
{
Util.addDom('div', { parent:actions, class:'material-icons ogl_button', child:'chevron_left', onclick:() =>
{
if(this.levelOffset > 1 - this.initialLevel)
{
this.levelOffset--;
this.displayLevel({ id:id, level:this.initialLevel + this.levelOffset, dom:details });
}
}});
Util.addDom('div', { parent:actions, class:'material-icons ogl_button', child:'close', onclick:() =>
{
this.levelOffset = 0;
this.displayLevel({ id:id, level:this.initialLevel, dom:details })
}});
Util.addDom('div', { parent:actions, class:'material-icons ogl_button', child:'chevron_right', onclick:() =>
{
this.levelOffset++;
this.displayLevel({ id:id, level:this.initialLevel + this.levelOffset, dom:details });
}});
}
Util.addDom('div', { parent:actions, class:'material-icons ogl_button', child:'lists', onclick:e =>
{
if(this.levelOffset >= 0)
{
//if(this.todoData) this.addToTodolist(tech, this.todoData);
e.target.classList.add('ogl_active');
this.todoData = {};
for(let i=this.initialLevel; i<=this.initialLevel+this.levelOffset; i++)
{
const data = this.getTechData(id, i, this.ogl.currentPlanet.obj.id);
this.todoData[i] = {};
this.todoData[i].level = (id == 407 || id == 408) ? 1 : i;
this.todoData[i].id = id;
this.todoData[i].metal = data.target.metal;
this.todoData[i].crystal = data.target.crystal;
this.todoData[i].deut = data.target.deut;
}
this.addToTodolist(this.todoData);
}
else
{
this.ogl._notification.addToQueue('Cannot lock previous levels', false);
}
}});
}
else
{
amount.addEventListener('input', () =>
{
setTimeout(() =>
{
const value = parseInt(amount.value) || 0;
amount.value = Math.min(99999, value);
if(amount.value)
{
setTimeout(() => this.displayLevel({ id:id, amount:value, dom:details }));
}
}, 100);
});
amount.setAttribute('onkeyup', 'checkIntInput(this, 1, 99999);event.stopPropagation();');
if(amount.parentNode.querySelector('.maximum')) amount.parentNode.querySelector('.maximum').addEventListener('click', () => amount.dispatchEvent(new Event('input')));
Util.addDom('div', { parent:actions, class:'material-icons ogl_button', child:'lists', onclick:e =>
{
this.todoData = {};
const number = amount.value && amount.value > 0 ? amount.value : 1;
const data = this.getTechData(id, number, this.ogl.currentPlanet.obj.id);
this.todoData[id] = {};
this.todoData[id].amount = parseInt(number) || 0;
this.todoData[id].id = id;
this.todoData[id].metal = data.target.metal;
this.todoData[id].crystal = data.target.crystal;
this.todoData[id].deut = data.target.deut;
this.addToTodolist(this.todoData);
}});
const queueDiv = Util.addDom('div', { parent:details.querySelector('.build_amount'), class:'ogl_queueShip' });
const btn10 = Util.addDom('div', { parent:queueDiv, title:this.ogl._lang.find('repeatQueue'), class:'ogl_button ogl_queue10 tooltip', child:'Repeat x', onclick:() =>
{
btn10.classList.add('ogl_disabled');
input10.classList.add('ogl_disabled');
const upgrade = () =>
{
fetch(scheduleBuildListEntryUrl+`&technologyId=${id}&amount=${amount.value || 1}&mode=1&token=${token}`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' },
})
.then(response => response.json())
.then(result =>
{
const buildLeft = parseInt(input10.value?.replace(/\D/g,'') || 0) - 1;
input10.value = buildLeft;
token = result.newAjaxToken;
window.stop();
if(buildLeft > 0) upgrade();
else
{
btn10.classList.remove('ogl_disabled');
input10.classList.remove('ogl_disabled');
}
});
}
upgrade();
}});
const input10 = Util.addDom('input', { type:'number', min:0, max:100, value:1, parent:queueDiv, oninput:() =>
{
const value = parseInt(input10.value?.replace(/\D/g,'') || 0);
const min = parseInt(input10.getAttribute('min'));
const max = parseInt(input10.getAttribute('max'));
input10.value = Math.min(Math.max(value, min), max);
}});
if(details.querySelector('.build-it_wrap .upgrade[disabled]'))
{
btn10.classList.add('ogl_disabled');
input10.classList.add('ogl_disabled');
}
}
// dock
if(id == 36)
{
const wreckfieldButton = details.querySelector('#wreckfield-btns');
if(wreckfieldButton)
{
const checkWreckfield = tries =>
{
//wreckfieldButton.innerText = '';
tries = tries || 0;
fetch(`https://${window.location.host}/game/index.php?page=ajax&component=repairlayer&asJson=1`,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(response =>
{
return response.text();
})
.then(response =>
{
try
{
let result = JSON.parse(response);
return result;
}
catch(e)
{
if(tries < 2)
{
setTimeout(() => checkWreckfield(tries+1), 1000);
}
else throw new Error(`Error, wrong serveur data: ${response}`);
}
})
.then(result =>
{
const shipList = {};
const txt = result.hasRepairOrder ? result.loca.shipsUndergoingRepairs : result.loca.availableShipsForRepair;
Util.addDom('div', { class:'ogl_button', parent:wreckfieldButton, child:txt.replace(':', ''), onclick:() =>
{
const container = Util.addDom('div');
Util.addDom('h2', { parent:container, child:txt });
for(let [shipID, value] of Object.entries(shipList))
{
Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, child:Util.formatNumber(value), parent:container });
}
this.ogl._popup.open(container);
}});
if(result.hasRepairOrder) // ships are ready or under repair
{
for(let [shipID, value] of Object.entries(result.shipsInRepairOrder))
{
shipList[shipID] = parseInt(value.amountTotal);
}
const btn = Util.addDom('div', { class:'ogl_button ogl_disabled', parent:wreckfieldButton, child:result.loca.submitButtonFinishRepair, onclick:() =>
{
fetch(result.ajaxEndpointReCommission,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(() =>
{
this.ogl.currentPlanet.obj.wreckfield = false;
this.ogl.save();
window.location.reload();
})
}});
if(result.canShipsBeDeployedButtonState)
{
btn.classList.remove('ogl_disabled');
Util.addDom('div', { parent:wreckfieldButton, child:result.autoDeployTimeForWF });
}
else
{
Util.addDom('div', { parent:wreckfieldButton, child:result.canShipsBeDeployedErrorText });
}
}
else if(result.hasWF) // there is a wreckfield
{
for(let [shipID, value] of Object.entries(result.shipData))
{
shipList[shipID] = parseInt(value.amount);
}
Util.addDom('div', { class:'ogl_button', parent:wreckfieldButton, child:result.loca.submitButtonRepair, onclick:() =>
{
fetch(result.ajaxEndpointStartRepairs,
{
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(() =>
{
const stats = this.ogl._stats.getDayStats(this.ogl._time.timeToKey(serverTime.getTime()));
const durationDom = document.querySelector('.repair_order time')?.getAttribute('datetime');
const duration = this.ogl._time.isoDurationToMs(durationDom) || 0;
for(let [shipID, amount] of Object.entries(shipList))
{
stats.raid = stats.raid || {};
stats.raid.gain = stats.raid.gain || {};
stats.raid.gain[shipID] = (stats.raid.gain[shipID] || 0) + amount;
}
this.ogl.currentPlanet.obj.wreckfield = serverTime.getTime() + Math.max(duration, 1800000); // 30 minutes minimum
this.ogl.save();
window.location.reload();
})
}});
}
});
wreckfieldButton.classList.add('ogl_active');
}
checkWreckfield();
}
else
{
this.ogl.currentPlanet.obj.wreckfield = false;
this.ogl.save();
}
}
this.displayLevel({ id:id, amount:amount ? this.initialLevel : 0, level:amount ? 0 : this.initialLevel, dom:details });
}
displayLevel(obj)
{
obj = obj || obj;
const id = obj.id || -1;
const level = obj.level || 0;
const amount = obj.amount || (level == 0 ? 1 : 0);
const dom = obj.dom || -1;
const data = this.getTechData(id, level, this.ogl.currentPlanet.obj.id);
const cumul = {};
const costs = dom.querySelector('.costs');
const narrow = dom.querySelector('.information .narrow') || dom.querySelector('.information ul');
const costsWrapper = costs.querySelector('.ogl_costsWrapper') || Util.addDom('div', { class:'ogl_costsWrapper' });
const range = `${this.initialLevel-1} <i class="material-icons">east</i> ${this.initialLevel + this.levelOffset}`;
const title = dom.querySelector('.information .level');
this.detailCumul[id] = this.detailCumul[id] || {};
this.detailCumul[id][level] = this.detailCumul[id][level] || {};
for(let [costID, cost] of Object.entries(data.target || {}))
{
this.detailCumul[id][level][costID] = cost;
}
for(let [cumulLvl, cumulCost] of Object.entries(this.detailCumul[id] || {}))
{
if(amount || (cumulLvl >= this.initialLevel && cumulLvl <= this.initialLevel + this.levelOffset))
{
Object.entries(cumulCost).forEach(entry =>
{
if(amount) cumul[entry[0]] = (entry[1] || 0) * amount;
else if(entry[0] == 'energy' || entry[0] == 'population') cumul[entry[0]] = entry[1];
else if(entry[0] !== 'timeresult') cumul[entry[0]] = (cumul[entry[0]] || 0) + entry[1];
});
}
}
cumul.timeresult = this.getTimeString(cumul.duration);
data.target.requiredPop = parseInt(narrow.querySelector('.required_population .value')?.getAttribute('data-value') || 0);
data.target.possibleStart = narrow.querySelector('.possible_build_start .value')?.innerText || 0;
if(unsafeWindow['technologyDetails'])
{
technologyDetails.id = id;
technologyDetails.lvl = level || amount;
}
const costsFragment = document.createDocumentFragment();
const header = Util.addDom('div', { class:'ogl_icon', parent:costsFragment });
Util.addDom('div', { parent:header });
Util.addDom('div', { parent:header, child:Math.max(level || amount, 1) });
if(!amount && id != 407 && id != 408) Util.addDom('div', { parent:header, child:range });
Util.addDom('div', { parent:header, class:'material-icons', child:'globe' });
let rawText;
['metal', 'crystal', 'deut', 'energy', 'population'].forEach(resource =>
{
if(costs.querySelector(`.${resource.replace('deut', 'deuterium')}`))
{
const diff = amount ? (this.ogl.currentPlanet.obj[resource] || 0) - ((data.target[resource] || 0) * amount) : (this.ogl.currentPlanet.obj[resource] || 0) - (cumul[resource] || 0);
const line = Util.addDom('div', { class:`ogl_icon ogl_${resource.replace('conso', 'energy')}`, parent:costsFragment });
// cost
const costValue = Util.formatToUnits(amount ? cumul[resource] : data.target[resource], 2);
Util.addDom('div', { class:'tooltip', title:Util.formatNumber(data.target[resource]), parent:line, child:costValue });
// cumul
if(!amount) Util.addDom('div', { parent:line, class:'ogl_text tooltip', title:Util.formatNumber(cumul[resource]), child:Util.formatToUnits(cumul[resource], 2) });
// diff
if(diff < 0) Util.addDom('div', { parent:line, class:'ogl_danger tooltip', title:Util.formatNumber(diff), child:Util.formatToUnits(diff, 2) });
else Util.addDom('div', { parent:line, class:'ogl_ok material-icons', child:'check' });
rawText = (rawText ? rawText + ' | ' : '') + `${Util.formatNumber(cumul[resource])} ${this.ogl._lang.find(resource)}`;
}
});
costs.addEventListener('click', () =>
{
navigator.clipboard.writeText(rawText);
fadeBox('Price copied');
});
const narrowKeys = { duration:'build_duration', conso:'additional_energy_consumption', prodEnergy:'energy_production', requiredPop:'required_population', possibleStart:'possible_build_start' };
const narrowFragment = document.createDocumentFragment();
for(let [key, value] of Object.entries(narrowKeys))
{
if(data.target[key] && (key != 'conso' || !costsFragment.querySelector('.ogl_energy')))
{
const text = (amount && key == 'duration') ? cumul.timeresult : key == 'requiredPop' ? Util.formatToUnits(data.target[key], 0) : key == 'duration' ? data.target.timeresult : key == 'possibleStart' ? data.target.possibleStart : Util.formatToUnits(data.target[key], false, true);
const readableValue = key == 'requiredPop' ? Util.formatToUnits(data.target[key], 0) : key == 'duration' ? data.target.timeresult : key == 'possibleStart' ? data.target.timeresult :isNaN(data.target[key]) ? data.target[key] : Util.formatNumber(data.target[key]);
const readableCumul = key == 'duration' ? cumul.timeresult : isNaN(cumul[key]) ? cumul[key] : Util.formatNumber(cumul[key]);
const tooltip =
key == 'possibleStart' ? 'Possible construction in...' :
level ?
`<div class="ogl_readableTooltip">Level ${level}: <b>${readableValue}</b><br>Level ${range} : <b>${readableCumul || readableValue}</b></div>` :
`<div class="ogl_readableTooltip">${this.ogl._lang.find(id)} x1: <b>${readableValue}</b><br>${this.ogl._lang.find(id)} x${amount} : <b>${readableCumul || readableValue}</div>`;
const li = Util.addDom('li', { class:value, parent:narrowFragment, child:'<strong></strong>' });
Util.addDom('span', { class:'value tooltip', 'data-value':data.target[key], title:tooltip, parent:li, child:text });
}
}
const msuValue = this.ogl.db.options.msu;
const msuline = Util.addDom('div', { class:`ogl_icon ogl_msu`, parent:costsFragment });
const msu = Util.getMSU(data.target.metal, data.target.crystal, data.target.deut, msuValue);
Util.addDom('div', { class:'tooltip', title:Util.formatNumber(msu), parent:msuline, child:Util.formatToUnits(msu, 2) });
const cumulMsu = Util.getMSU(cumul.metal, cumul.crystal, cumul.deut, msuValue);
if(!amount) Util.addDom('div', { parent:msuline, class:'ogl_text tooltip', title:Util.formatNumber(cumulMsu), child:Util.formatToUnits(cumulMsu, 2) });
requestAnimationFrame(() =>
{
if(title) title.innerHTML = range;
if(this.ogl.currentPlanet.obj.todolist[id]?.[level])
{
dom.querySelector('.ogl_actions .ogl_button:last-child').classList.add('ogl_active');
}
else
{
dom.querySelector('.ogl_actions .ogl_button:last-child').classList.remove('ogl_active');
}
costsWrapper.innerText = '';
costsWrapper.appendChild(costsFragment);
narrow.innerText = '';
narrow.appendChild(narrowFragment);
if(!costsWrapper.parentElement)
{
costs.appendChild(costsWrapper);
}
initTooltips();
});
}
addToTodolist(data)
{
this.ogl.currentPlanet.obj.todolist = this.ogl.currentPlanet.obj.todolist || {};
Object.values(data).forEach(entry =>
{
const todolist = this.ogl.currentPlanet.obj.todolist;
const entryLvl = entry.level || Date.now() + performance.now();
todolist[entry.id] = todolist[entry.id] || {};
todolist[entry.id][entryLvl] = todolist[entry.id][entryLvl] || {};
todolist[entry.id][entryLvl].id = entry.id;
todolist[entry.id][entryLvl].amount = entry.amount || 0;
todolist[entry.id][entryLvl].level = entryLvl;
todolist[entry.id][entryLvl].cost =
{
metal:entry.metal,
crystal:entry.crystal,
deut:entry.deut,
}
});
this.checkTodolist();
}
checkTodolist()
{
let requireUpdate = false;
Object.values(this.ogl._dom.planet).forEach(planet =>
{
const id = planet._ogl.id;
const isMoon = planet._ogl.type == 'moon';
const todolist = this.ogl.db.myPlanets[id]?.todolist || {};
planet._ogl.sideIcon.querySelectorAll('.ogl_todoIcon').forEach(e => e.remove());
const count = Object.values(todolist).reduce((accumulator, currentValue) => { return accumulator + Object.keys(currentValue).length; }, 0);
const total = Object.values(todolist).flatMap(Object.values).reduce((acc, item) => acc + (item.cost?.metal || 0) + (item.cost?.crystal || 0) + (item.cost?.deut || 0), 0);
Object.values(todolist).forEach((building, index) =>
{
if(index == 0)
{
const icon = Util.addDom('div', { class:'material-icons ogl_todoIcon tooltip', child:'lists', 'data-list':`${count}`, parent:planet._ogl.sideIcon, onclick:() =>
{
this.openTodolist(todolist, `${planet._ogl.coords}:${isMoon ? 3 : 1}`, id);
}});
if(total <= 0) icon.classList.add('ogl_ok');
}
});
});
document.querySelectorAll('.technology[data-technology]').forEach(techDom =>
{
let techID = techDom.getAttribute('data-technology');
let techLvL = techDom.querySelector('.targetlevel') || techDom.querySelector('.level');
if(!techLvL) return;
techLvL = parseInt(techLvL.getAttribute('data-value'));
Object.keys(this.ogl.currentPlanet.obj.todolist?.[techID] || {}).forEach(key =>
{
if(techLvL >= parseInt(key))
{
delete this.ogl.currentPlanet.obj.todolist[techID][key];
if(Object.values(this.ogl.currentPlanet.obj.todolist[techID]).length < 1)
{
delete this.ogl.currentPlanet.obj.todolist[techID];
requireUpdate = true;
}
}
});
});
if(requireUpdate)
{
this.checkTodolist();
}
}
openTodolist(data, coords, id)
{
let toSend = {};
const splitted = coords.split(':');
const container = Util.addDom('div', {class:'ogl_todoList', child:`<h2>Todolist ${splitted[3] == 1 ? 'planet' : 'moon'} [${splitted[0]}:${splitted[1]}:${splitted[2]}]</h2>`});
const leftDiv = Util.addDom('div', { parent:container });
const rightDiv = Util.addDom('div', { parent:container, class:'ogl_actions' });
let totalReq = {};
let totalSelected = {};
let updateHeader = (blockData, header, content, footer, block) =>
{
setTimeout(() =>
{
const checkedCount = content.querySelectorAll('input:checked').length;
const maxCount = Object.keys(blockData).length;
const blockID = Object.values(blockData)[0]?.id;
if(!maxCount)
{
block.remove();
Object.keys(toSend).filter(k => k.startsWith(blockID+'_')).forEach(k => delete toSend[k]);
delete this.ogl.db.myPlanets[id].todolist[blockID];
this.checkTodolist();
return;
}
header.innerHTML = this.ogl.db.serverData[blockID];
header.innerHTML += ` (<b>${checkedCount}</b>/${maxCount})`;
if(checkedCount != maxCount && footer && footer.querySelector('input:checked')) footer.querySelector('input:checked').checked = false;
if(Object.entries(toSend).length > 0) sendButton.classList.remove('ogl_disabled');
else sendButton.classList.add('ogl_disabled');
updateTotal();
});
}
let updateTotal = () =>
{
totalDiv.innerHTML = `
<div class="ogl_grid">
<div class="ogl_icon"><div class="material-icons">sigma</div><div>Required</div><div>Selected</div></div>
<div class="ogl_icon ogl_metal"><div>${Util.formatToUnits(totalReq.metal || 0)}</div><div>${Util.formatToUnits(totalSelected.metal || 0)}</div></div>
<div class="ogl_icon ogl_crystal"><div>${Util.formatToUnits(totalReq.crystal || 0)}</div><div>${Util.formatToUnits(totalSelected.crystal || 0)}</div></div>
<div class="ogl_icon ogl_deut"><div>${Util.formatToUnits(totalReq.deut || 0)}</div><div>${Util.formatToUnits(totalSelected.deut || 0)}</div></div>
</div>
`;
}
let updateFooter = (footer, content, cumul) =>
{
setTimeout(() =>
{
footer.innerHTML = '';
let line = Util.addDom('div', { class:'ogl_line ogl_blockRecap', parent:footer, child:
`
<div>all</div>
<div class="ogl_icon ogl_metal">${Util.formatToUnits(cumul.metal, 2)}</div>
<div class="ogl_icon ogl_crystal">${Util.formatToUnits(cumul.crystal, 2)}</div>
<div class="ogl_icon ogl_deut">${Util.formatToUnits(cumul.deut, 2)}</div>
<label></label>
` });
// select block
let input = Util.addDom('input', { type:'checkbox', parent:line.querySelector('label'), oninput:() =>
{
if(input.checked) content.querySelectorAll('input').forEach(input => { if(input.checked != true) input.click(); });
else content.querySelectorAll('input').forEach(input => { if(input.checked == true) input.click(); });
}});
// send block
Util.addDom('button', { class:'material-icons', parent:line, child:'cube-send', onclick:() =>
{
content.querySelectorAll('input').forEach(input => { if(input.checked != true) input.click(); });
setTimeout(() => container.querySelector('.ogl_button').click(), 50);
}});
// remove block
Util.addDom('button', { class:'material-icons ogl_removeTodo', parent:line, child:'close', onclick:() =>
{
content.querySelectorAll('.ogl_removeTodo').forEach(button => { button.click(); });
setTimeout(() => updateTotal(), 10);
}});
});
}
Object.values(data).forEach(blockData =>
{
const block = Util.addDom('div', { class:'ogl_tech', parent:leftDiv });
const header = Util.addDom('h3', { parent:block, onclick:() => block.classList.toggle('ogl_active') });
const content = Util.addDom('div', { parent:block });
const footer = Util.addDom('footer', { parent:block });
const cumul = {};
Object.values(blockData).forEach(todo =>
{
const displayedCell = todo.amount || todo.level;
const key = `${todo.id}_${todo.level}`;
let line = Util.addDom('div', { class:'ogl_line', 'data-parent':this.ogl.db.serverData[todo.id], parent:content, child:
`
<div>${displayedCell}</div><div class="ogl_icon ogl_metal">${Util.formatToUnits(todo.cost?.metal, 2)}</div>
<div class="ogl_icon ogl_crystal">${Util.formatToUnits(todo.cost?.crystal, 2)}</div>
<div class="ogl_icon ogl_deut">${Util.formatToUnits(todo.cost?.deut, 2)}</div>
<label></label>
` });
cumul.metal = (cumul.metal || 0) + (todo.cost?.metal || 0);
cumul.crystal = (cumul.crystal || 0) + (todo.cost?.crystal || 0);
cumul.deut = (cumul.deut || 0) + (todo.cost?.deut || 0);
totalReq.metal = (totalReq.metal || 0) + (todo.cost?.metal || 0);
totalReq.crystal = (totalReq.crystal || 0) + (todo.cost?.crystal || 0);
totalReq.deut = (totalReq.deut || 0) + (todo.cost?.deut || 0);
// select line
let input = Util.addDom('input', { type:'checkbox', parent:line.querySelector('label'), oninput:() =>
{
if(input.checked)
{
toSend[key] = todo;
input.setAttribute('data-clicked', performance.now());
totalSelected.metal = (totalSelected.metal || 0) + (todo.cost?.metal || 0);
totalSelected.crystal = (totalSelected.crystal || 0) + (todo.cost?.crystal || 0);
totalSelected.deut = (totalSelected.deut || 0) + (todo.cost?.deut || 0);
}
else
{
delete toSend[key];
input.removeAttribute('data-clicked');
totalSelected.metal = (totalSelected.metal || 0) - (todo.cost?.metal || 0);
totalSelected.crystal = (totalSelected.crystal || 0) - (todo.cost?.crystal || 0);
totalSelected.deut = (totalSelected.deut || 0) - (todo.cost?.deut || 0);
}
leftDiv.querySelectorAll('label').forEach(e => e.removeAttribute('data-order'));
Array.from(leftDiv.querySelectorAll('.ogl_tech > div input:checked')).sort((a, b) => a.getAttribute('data-clicked') - b.getAttribute('data-clicked')).forEach((e, index) =>
{
e.parentNode.setAttribute('data-order', index+1);
});
updateHeader(blockData, header, content, footer, block);
}});
// send line
Util.addDom('button', { class:'material-icons', parent:line, child:'cube-send', onclick:() =>
{
input.click();
setTimeout(() => container.querySelector('.ogl_button').click(), 50);
}});
// remove line
Util.addDom('button', { class:'material-icons ogl_removeTodo', parent:line, child:'close', onclick:() =>
{
line.remove();
cumul.metal = (cumul.metal || 0) - (todo.cost?.metal || 0);
cumul.crystal = (cumul.crystal || 0) - (todo.cost?.crystal || 0);
cumul.deut = (cumul.deut || 0) - (todo.cost?.deut || 0);
totalSelected.metal = (totalSelected.metal || 0) - (todo.cost?.metal || 0);
totalSelected.crystal = (totalSelected.crystal || 0) - (todo.cost?.crystal || 0);
totalSelected.deut = (totalSelected.deut || 0) - (todo.cost?.deut || 0);
delete toSend[key];
delete this.ogl.db.myPlanets[id].todolist[todo.id][todo.level];
if(Object.keys(this.ogl.db.myPlanets[id].todolist[todo.id] || {}).length <= 0)
{
delete this.ogl.db.myPlanets[id].todolist[todo.id];
block.remove();
}
if(Object.keys(ogl.db.myPlanets[id].todolist || {}).length <= 0)
{
this.ogl.db.myPlanets[id].todolist = {};
this.ogl._popup.close();
}
Array.from(leftDiv.querySelectorAll('.ogl_tech > div input:checked')).sort((a, b) => a.getAttribute('data-clicked') - b.getAttribute('data-clicked')).forEach((e, index) =>
{
e.parentNode.setAttribute('data-order', index+1);
});
if(unsafeWindow['technologyDetails'])
{
if(id == this.ogl.currentPlanet.obj.id && document.querySelector('#technologydetails .ogl_actions .ogl_active'))
{
document.querySelector('#technologydetails .ogl_actions .ogl_active').classList.remove('ogl_active');
}
}
updateHeader(blockData, header, content, footer, block);
updateFooter(footer, content, cumul);
this.checkTodolist();
}});
});
updateHeader(blockData, header, content, footer, block);
updateFooter(footer, content, cumul);
});
let url = `https://${window.location.host}/game/index.php?page=ingame&component=fleetdispatch&galaxy=${splitted[0]}&system=${splitted[1]}&position=${splitted[2]}&oglmode=3&targetid=${id}&type=${splitted[3]}`;
let sendButton = Util.addDom('button', { class:'ogl_button ogl_disabled', parent:rightDiv, child:'Send selection <i class="material-icons">cube-send</i>', onclick:() =>
{
this.ogl.cache.toSend = Object.values(toSend);
if(substractButton.querySelector('input').checked) url += '&substractMode=true';
window.location.href = url;
rightDiv.querySelectorAll('.ogl_button').forEach(e => e.classList.add('ogl_disabled'));
}});
Util.addDom('button', { class:'ogl_button', parent:rightDiv, child:'Send all <i class="material-icons">cube-send</i>', onclick:() =>
{
leftDiv.querySelectorAll('input').forEach(input => { if(input.checked != true) input.click(); });
setTimeout(() =>
{
this.ogl.cache.toSend = Object.values(toSend);
rightDiv.querySelectorAll('.ogl_button').forEach(e => e.classList.add('ogl_disabled'));
if(substractButton.querySelector('input').checked) url += '&substractMode=true';
window.location.href = url;
}, 100);
}});
Util.addDom('button', { class:'ogl_button ogl_removeTodo', parent:rightDiv, child:'Remove all <i class="material-icons">close</i>', onclick:() =>
{
this.ogl.db.myPlanets[id].todolist = {};
this.ogl._popup.close();
this.checkTodolist();
if(unsafeWindow['technologyDetails'])
{
if(id == this.ogl.currentPlanet.obj.id && document.querySelector('#technologydetails .ogl_actions .ogl_active'))
{
document.querySelector('#technologydetails .ogl_actions .ogl_active').classList.remove('ogl_active');
}
}
}});
Util.addDom('hr', { parent:rightDiv });
let substractButton = Util.addDom('label', { class:'ogl_button', parent:rightDiv, child:'<input type="checkbox">Substract planet resources' });
const totalDiv = Util.addDom('div', { class:'ogl_totalRequired', parent:rightDiv });
this.ogl._popup.open(container);
}
getTechData(id, level, planetID)
{
if(!id) return;
const data = Datafinder.getTech(id);
const planetData = this.ogl.db.myPlanets[planetID] || {};
let baseLabs = [];
let bestLabs = 0;
let labRequired =
{
// you can't use a lab with a too low level for the tech
113:1, 120:1, 121:4, 114:7, 122:4, 115:1, 117:2, 118:7,
106:3, 108:1, 124:3, 123:10, 199:12, 109:4, 110:6, 111:2,
}
document.querySelectorAll('.smallplanet').forEach(line =>
{
const coloID = line.getAttribute('id').replace('planet-', '');
const colo = this.ogl.db.myPlanets[coloID];
if(!colo) return;
if(planetID != coloID && colo[31] >= labRequired[id]) baseLabs.push(colo[31]); // base labo
});
baseLabs.sort((a, b) => b - a);
baseLabs = baseLabs.slice(0, Math.min(baseLabs.length, planetData[123]));
if(baseLabs.length) bestLabs = baseLabs.reduce((a, b) => a + b);
const planet = {};
planet.lifeform = planetData.lifeform || 0;
//planet.activeLF = planetData.activeLFTechs || [];
this.totalLab = (planetData[31] || 0) + bestLabs;
const tech = {};
tech.id = id;
tech.isBaseBuilding = tech.id < 100;
tech.isBaseResearch = tech.id > 100 && tech.id <= 199;
tech.isBaseShip = tech.id > 200 && tech.id <= 299;
tech.isBaseDef = tech.id > 400 && tech.id <= 599;
tech.isLfBuilding = (tech.id > 11100 && tech.id <= 11199) || (tech.id > 12100 && tech.id <= 12199) || (tech.id > 13100 && tech.id <= 13199) || (tech.id > 14100 && tech.id <= 14199);
tech.isLfResearch = (tech.id > 11200 && tech.id <= 11299) || (tech.id > 12200 && tech.id <= 12299) || (tech.id > 13200 && tech.id <= 13299) || (tech.id > 14200 && tech.id <= 14299);
tech.base = {};
tech.base.metal = data.metal || 0;
tech.base.crystal = data.crystal || 0;
tech.base.deut = data.deut || 0;
tech.base.energy = data.energy || 0;
tech.base.duration = data.durationbase || 0;
tech.base.conso = data.conso || 0;
tech.base.population = data.bonus1BaseValue || 0;
tech.factor = {};
tech.factor.price = data.priceFactor || 2;
tech.factor.duration = data.durationfactor || 2;
tech.factor.energy = data.energyFactor || data.energyIncreaseFactor || 2;
tech.factor.population = data.bonus1IncreaseFactor || 2;
tech.bonus = {};
tech.bonus.price = 0;
tech.bonus.duration = 0;
tech.bonus.classDuration = 0;
tech.bonus.eventDuration = 0;
tech.bonus.technocrat = 0;
tech.bonus.engineer = 0;
tech.bonus.conso = 0;
tech.bonus.prodEnergy = 0;
if(this.ogl.account.class == 1) tech.bonus.prodEnergy += .1; // 10% rocktal energy bonus
if(this.ogl.db.allianceClass == 2) tech.bonus.prodEnergy += .05; // 5% trader alliance bonus
//tech.bonus.race = localBonusRaceLevel * (1 + localBonus11111 + localBonus13107 + localBonus13111);
if(planet.lifeform == 2)
{
// rocktal chamber
tech.bonus.prodEnergy += planetData[12107] * Datafinder.getTech(12107).bonus1BaseValue / 100;
tech.bonus.conso += planetData[12107] * Datafinder.getTech(12107).bonus2BaseValue / 100;
if(tech.isLfBuilding)
{
// rocktal monument
tech.bonus.price += planetData[12108] * Datafinder.getTech(12108).bonus1BaseValue / 100;
tech.bonus.duration += planetData[12108] * Datafinder.getTech(12108).bonus2BaseValue / 100;
}
}
else if(planet.lifeform == 3)
{
tech.bonus.prodEnergy += planetData[13107] * Datafinder.getTech(13107).bonus1BaseValue / 100;
if(tech.isBaseShip || tech.isBaseDef)
{
tech.bonus.duration += planetData[13106] * Datafinder.getTech(13106).bonus1BaseValue / 100; // meca center
}
}
if(tech.isBaseResearch && document.querySelector('.technology .acceleration')) tech.bonus.eventDuration += parseInt(document.querySelector('.technology .acceleration').getAttribute('data-value')) / 100; // research speed event bonus
//if(tech.isBaseResearch && this.ogl.account.class == 3) tech.bonus.classDuration += 0.25 * (1 + cumul[14218] * Datafinder.getTech(14218).bonus1BaseValue / 100 * tech.bonus.race); // explo class research speed bonus
if(tech.isBaseResearch && this.ogl.account.class == 3) tech.bonus.classDuration += .25 * (1 + (this.ogl.db.lfBonuses?.Characterclasses3?.bonus || 0) / 100); // explo class research speed bonus
if(tech.isBaseResearch && document.querySelector('#officers .technocrat.on')) tech.bonus.technocrat += 0.25; // technocrat research speed bonus
if(document.querySelector('#officers .engineer.on')) tech.bonus.engineer += 0.10; // engineer energy prod bonus
if(tech.isLfResearch)
{
if(planet.lifeform == 1) // human
{
tech.bonus.price += planetData[11103] * Datafinder.getTech(11103).bonus1BaseValue / 100;
tech.bonus.duration += planetData[11103] * Datafinder.getTech(11103).bonus2BaseValue / 100;
}
else if(planet.lifeform == 2) // rocktal
{
tech.bonus.price += planetData[12103] * Datafinder.getTech(12103).bonus1BaseValue / 100;
tech.bonus.duration += planetData[12103] * Datafinder.getTech(12103).bonus2BaseValue / 100;
}
else if(planet.lifeform == 3) // meca
{
tech.bonus.price += planetData[13103] * Datafinder.getTech(13103).bonus1BaseValue / 100;
tech.bonus.duration += planetData[13103] * Datafinder.getTech(13103).bonus2BaseValue / 100;
}
else if(planet.lifeform == 4) // kaelesh
{
tech.bonus.price += planetData[14103] * Datafinder.getTech(14103).bonus1BaseValue / 100;
tech.bonus.duration += planetData[14103] * Datafinder.getTech(14103).bonus2BaseValue / 100;
}
tech.bonus.price += (this.ogl.db.lfBonuses?.LfResearch?.cost || 0) / 100;
tech.bonus.duration += (this.ogl.db.lfBonuses?.LfResearch?.duration || 0) / 100;
}
if(planet.lifeform == 2 && (tech.id == 1 || tech.id == 2 || tech.id == 3 || tech.id == 4 || tech.id == 12 || tech.id == 12101 || tech.id == 12102))
{
tech.bonus.price += planetData[12111] * Datafinder.getTech(12111).bonus1BaseValue / 100;
}
if(tech.isBaseResearch || tech.isBaseDef || tech.isBaseShip)
{
tech.bonus.price += (this.ogl.db.lfBonuses?.[tech.id]?.cost || 0) / 100;
tech.bonus.duration += (this.ogl.db.lfBonuses?.[tech.id]?.duration || 0) / 100;
}
tech.target = {};
if(tech.isBaseBuilding || tech.isBaseResearch)
{
const rawMetal = Math.floor(tech.base.metal * Math.pow(tech.factor.price, level - 1));
const rawCrystal = Math.floor(tech.base.crystal * Math.pow(tech.factor.price, level - 1));
const rawDeut = Math.floor(tech.base.deut * Math.pow(tech.factor.price, level - 1));
tech.target.metal = Math.floor(rawMetal * (1 - tech.bonus.price));
tech.target.crystal = Math.floor(rawCrystal * (1 - tech.bonus.price));
tech.target.deut = Math.floor(rawDeut * (1 - tech.bonus.price));
tech.target.energy = Math.floor(tech.base.energy * Math.pow(tech.factor.energy, level - 1));
if(tech.id == 1 || tech.id == 2) tech.target.conso = Math.ceil(10 * level * Math.pow(1.1, level)) - Math.ceil(10 * (level-1) * Math.pow(1.1, level-1));
if(tech.id == 3) tech.target.conso = Math.ceil(20 * level * Math.pow(1.1, level)) - Math.ceil(20 * (level-1) * Math.pow(1.1, level-1));
if(tech.id == 4) tech.target.prodEnergy = Math.floor(20 * level * Math.pow(1.1, level)) - Math.floor(20 * (level-1) * Math.pow(1.1, level-1));
if(tech.id == 12) tech.target.prodEnergy = Math.floor(30 * level * Math.pow((1.05 + (planetData[113] || 0) * 0.01), level)) - Math.floor(30 * (level-1) * Math.pow((1.05 + (planetData[113] || 0) * 0.01), level-1));
if(tech.isBaseBuilding) tech.target.duration = (rawMetal + rawCrystal) / (2500 * Math.max((id == 41 || id == 42 || id == 43 || id == 15) ? 1 : 4 - level / 2, 1) * (1 + (id == 14 ? this.initialLevel+this.levelOffset-1 : planetData[14]) || 0) * (Math.pow(2, (id == 15 ? this.initialLevel+this.levelOffset-1 : planetData[15]) || 0))) * 3600 * 1000;
else tech.target.duration = (rawMetal + rawCrystal) / (1000 * (1 + (planetData[31] || 0) + bestLabs)) * 3600 * 1000;
}
else if(tech.isLfBuilding || tech.isLfResearch)
{
tech.target.metal = Math.floor(Math.floor(tech.base.metal * Math.pow(tech.factor.price, level - 1) * level) * (1 - tech.bonus.price));
tech.target.crystal = Math.floor(Math.floor(tech.base.crystal * Math.pow(tech.factor.price, level - 1) * level) * (1 - tech.bonus.price));
tech.target.deut = Math.floor(Math.floor(tech.base.deut * Math.pow(tech.factor.price, level - 1) * level) * (1 - tech.bonus.price));
tech.target.energy = Math.floor(Math.floor(level * tech.base.energy * Math.pow(tech.factor.energy, level) * (1 - tech.bonus.price)));
tech.target.population = Math.floor(Math.floor(tech.base.population * Math.pow(tech.factor.population, level-1) * (1 - tech.bonus.price)));
if(level < 2) tech.target.conso = Math.floor(level * tech.base.energy);
else tech.target.conso = Math.floor(Math.floor(level * tech.base.energy * Math.pow(tech.factor.energy, level) - (level-1) * tech.base.energy * Math.pow(tech.factor.energy, level-1)));
if(tech.isLfBuilding) tech.target.duration = Math.floor(level * tech.base.duration * 1000 * (1 / ((1 + (planetData[14] || 0)) * (Math.pow(2, planetData[15] || 0)))) * Math.pow(tech.factor.duration, level));
else tech.target.duration = Math.floor(level * tech.base.duration * 1000 * Math.pow(tech.factor.duration, level));
}
else if(tech.isBaseShip || tech.isBaseDef)
{
const amount = level || 1;
tech.target.metal = tech.base.metal * amount;
tech.target.crystal = tech.base.crystal * amount;
tech.target.deut = tech.base.deut * amount;
tech.target.duration = ((tech.base.metal + tech.base.crystal) / 5000) * (2 / (1 + planetData[21] || 0)) * Math.pow(0.5, (planetData[15] || 0)) * 3600 * 1000;
if(tech.id == 212) tech.target.prodEnergy = Math.floor(((planetData.temperature + 40 + planetData.temperature) / 2 + 160) / 6) * amount;
}
if(this.ogl.db.options.debugMode)
{
console.log(JSON.parse(JSON.stringify(tech)));
}
tech.target.prodEnergy = Math.floor(tech.target.prodEnergy * (1 + tech.bonus.prodEnergy + tech.bonus.engineer)) || 0;
tech.target.conso = -Math.ceil(tech.target.conso * (1 - tech.bonus.conso)) || 0;
tech.target.duration = tech.target.duration / (this.ogl.server.economySpeed * (tech.isBaseResearch ? this.ogl.db.serverData.researchSpeed : 1)) * (1 - tech.bonus.eventDuration) * (1 - tech.bonus.classDuration) * (1 - tech.bonus.technocrat) * (1 - Math.min(tech.bonus.duration, .99));
tech.target.duration = Math.max(tech.target.duration, 1000);
if(tech.isBaseShip || tech.isBaseDef)
{
tech.target.duration = Math.floor(tech.target.duration / 1000) * 1000;
tech.target.duration = Math.max(tech.target.duration, 1000) * (level || 1);
}
tech.target.timeresult = this.getTimeString(tech.target.duration);
return tech;
}
getTimeString(duration)
{
let seconds = duration / 1000;
let w = Math.floor(seconds / (3600*24*7));
let d = Math.floor(seconds % (3600*24*7) / (3600*24));
let h = Math.floor(seconds % (3600*24) / 3600);
let m = Math.floor(seconds % 3600 / 60);
let s = Math.floor(seconds % 60);
let timeString = '';
let displayed = 0;
if(w > 0 && displayed < 3) { timeString += `${w}${LocalizationStrings.timeunits.short.week} `; displayed++; }
if(d > 0 && displayed < 3) { timeString += `${d}${LocalizationStrings.timeunits.short.day} `; displayed++; }
if(h > 0 && displayed < 3) { timeString += `${h}${LocalizationStrings.timeunits.short.hour} `; displayed++; }
if(m > 0 && displayed < 3) { timeString += `${m}${LocalizationStrings.timeunits.short.minute} `; displayed++; }
if(s > 0 && displayed < 3) { timeString += `${s}${LocalizationStrings.timeunits.short.second}`; displayed++; }
return timeString;
}
checkProductionBoxes()
{
this.ogl.currentPlanet.obj.upgrades = this.ogl.currentPlanet.obj.upgrades || {};
Object.entries(this.ogl._time.productionBoxes).forEach(box =>
{
const dom = document.querySelectorAll(`#${box[1]} .countdown`);
if(!dom) return;
const dateTime = dom[dom.length-1]?.getAttribute('datetime');
if(!dateTime) return;
const techType = box[1] == 'productionboxbuildingcomponent' ? 'baseBuilding' : box[1] == 'productionboxresearchcomponent' ? 'baseResearch' : box[1] == 'productionboxshipyardcomponent' ? 'ship' : box[1] == 'productionboxlfbuildingcomponent' ? 'lfBuilding' : box[1] == 'productionboxlfresearchcomponent' ? 'lfResearch' : box[1] == 'productionboxextendedshipyardcomponent' ? 'mechaShip' : 'unknown';
const [, years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0] = dateTime.match(/P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?T?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?/) || [];
const totalSeconds = (years * 31536000) + (months * 2592000) + (weeks * 604800) + (days * 86400) + (hours * 3600) + (minutes * 60) + parseFloat(seconds);
const itemEndTime = serverTime.getTime() + totalSeconds * 1000;
const timeObj = this.ogl._time.getObj(itemEndTime, 'server');
const endDate = this.ogl.db.options.useClientTime ? timeObj.client : timeObj.server;
const div = document.querySelector(`#${[box[1]]} .content`);
div.classList.add(`ogl_${techType}`);
let content = `<span>${new Date(endDate).toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})} </span>${new Date(endDate).toLocaleTimeString('de-DE')}`;
Util.addDom('time', { class:'ogl_timeBox', prepend:div.querySelector('.build-faster').parentNode, child:content, 'data-time-server':timeObj.server, 'data-time-client':timeObj.client });
const boxID = `${techType}Queue-${this.ogl.currentPlanet.obj.id}`;
const arrival = timeObj.server;
const notifIcon = Util.addDom('div', { prepend:div.querySelector('.build-faster').parentNode, class:this.ogl.db.browserNotificationList[boxID] ? 'ogl_clockNotif ogl_button ogl_active': 'ogl_clockNotif ogl_button', onclick:e =>
{
const browserNotification = {};
browserNotification.id = boxID;
browserNotification.arrivalTime = arrival;
browserNotification.message = `[${this.ogl.currentPlanet.obj.coords}] ${this.ogl.currentPlanet.obj.type} : Production complete`;
this.ogl._notification.addNotification(browserNotification, e.target);
}});
if(this.ogl.db.browserNotificationList[boxID] && Math.abs(this.ogl.db.browserNotificationList[boxID].arrivalTime - arrival) > 5000)
{
notifIcon.classList.add('ogl_altered');
}
if(techType == 'baseResearch')
{
const element = document.querySelector(`#${box[1]} .queuePic`).parentNode;
const lvl = document.querySelector(`#${box[1]} .level`).innerText;
const id = element.getAttribute('onclick')?.match(/([0-9]+)/)[0];
const coords = element.getAttribute('onclick')?.match(/[([0-9:]+]/)?.[0]?.slice(1, -1);
if(!id || !lvl || !coords) return;
const upgrade = {};
upgrade.id = id;
upgrade.name = this.ogl.db.serverData[id] || id;
upgrade.lvl = lvl;
upgrade.end = itemEndTime;
upgrade.type = techType;
if(coords && coords != this.ogl.currentPlanet.obj.coords)
{
const pid = Object.values(this.ogl.db.myPlanets).find(e => e.coords == coords && e.type == "planet").id;
this.ogl.db.myPlanets[pid].upgrades = this.ogl.db.myPlanets[pid].upgrades || [];
this.ogl.db.myPlanets[pid].upgrades[techType] = [upgrade];
}
else if(coords == this.ogl.currentPlanet.obj.coords && this.ogl.currentPlanet.obj.type != 'moon')
{
this.ogl.currentPlanet.obj.upgrades = this.ogl.currentPlanet.obj.upgrades || [];
this.ogl.currentPlanet.obj.upgrades[techType] = [upgrade];
}
}
let totalEndTime = itemEndTime;
div.querySelectorAll('.queuePic').forEach(queueElement =>
{
const id = queueElement.closest('a')?.getAttribute('onclick')?.match(/([0-9]+)/)[0];
if(!id) return;
const lvl = parseInt(queueElement.parentElement.innerText || 0);
const data = this.getTechData(id, lvl, this.ogl.currentPlanet.obj.id);
if(!data) return;
totalEndTime += data.target.duration;
});
const totalTimeObj = this.ogl._time.getObj(Math.ceil(totalEndTime), 'server');
const totalEndDate = this.ogl.db.options.useClientTime ? totalTimeObj.client : totalTimeObj.server;
let totalContent = `<span>${new Date(totalEndDate).toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit', year:'numeric'})} </span>${new Date(totalEndDate).toLocaleTimeString('de-DE')}`;
Util.addDom('time', { class:'ogl_timeBox', parent:div, child:totalContent, 'data-time-server':totalTimeObj.server, 'data-time-client':totalTimeObj.client });
});
document.querySelectorAll('.queuePic').forEach(element =>
{
const id = element.closest('a')?.getAttribute('onclick')?.match(/([0-9]+)/)[0];
if(!id) return;
const technology = document.querySelector(`.technology[data-technology="${id}"]`);
if(!technology) return;
technology.classList.add('ogl_active');
});
}
calcMaxCrawler()
{
const planet = this.ogl.currentPlanet.obj;
const base = (planet[1] + planet[2] + planet[3]) * 8;
const lf31BonusValue = this.ogl.db.lfBonuses?.MiscImprovedCrawler?.bonus || 0;
const lf36BonusValue = this.ogl.account.class === 1 ? (this.ogl.db.lfBonuses?.Characterclasses1?.bonus || 0) : 0;
const lf36AmountBonus = (this.ogl.account.hasGeologist && this.ogl.account.class === 1) ? (1.1 + (.1 * lf36BonusValue / 100)) : 1;
const result = {};
let i = this.ogl.account.class === 1 ? 1.5 : 1;
for (i; i>0.9; i = i-0.1)
{
const totalBonus = (lf31BonusValue / 100) + (0.5 * lf36BonusValue / 100);
const crawlerProd = (0.02 * (1.5 + totalBonus)) * i;
const crawlerMaxProdTreshold = Math.ceil(50 / crawlerProd);
const maxAmount = Math.min(Math.floor(base * lf36AmountBonus), crawlerMaxProdTreshold);
result[Math.round(i * 100)] = maxAmount;
}
return result;
}
}
class StatsManager extends Manager
{
load()
{
this.ogl.db.stats = this.ogl.db.stats || {};
this.types = ['raid', 'expe', 'discovery', 'debris', 'debris16', 'blackhole'];
this.displayedRange = { start:this.ogl._time.timeToKey(serverTime.getTime()), end:this.ogl._time.timeToKey(serverTime.getTime()) };
this.showMiniRecap();
}
showMiniRecap()
{
const data = this.filterStatsByDateRange(this.ogl._time.timeToKey(serverTime.getTime()), this.ogl._time.timeToKey(serverTime.getTime()));
const total = { metal:0, crystal:0, deut:0, dm:0, artefact:0, msu:0 };
['expe', 'debris16', 'raid', 'debris', 'discovery'].forEach(key =>
{
for(let [gainID, value] of Object.entries(Object.values(data)[0]?.[key]?.gain || {}))
{
if(!isNaN(gainID))
{
const shipData = Datafinder.getTech(Math.abs(gainID));
const shipFactor = key == 'expe' && parseInt(gainID) > 0 ? this.ogl.db.options.expeditionShipRatio / 100 : 1;
const sign = parseInt(gainID) > 0 ? 1 : -1;
const isIgnored = sign < 0 && key == 'expe' && this.ogl.db.options.ignoreExpeShipsLoss;
if(!isIgnored)
{
total.metal += ((shipData.metal || 0) * value * shipFactor * sign);
total.crystal += ((shipData.crystal || 0) * value * shipFactor * sign);
total.deut += ((shipData.deut || 0) * value * shipFactor * sign);
}
}
else
{
if(gainID == 'metal') total.metal += (value || 0);
else if (gainID == 'crystal') total.crystal += (value || 0);
else if (gainID == 'deut') total.deut += (value || 0);
else if (gainID == 'dm') total.dm += (value || 0);
else if (gainID == 'artefact') total.artefact += (value || 0);
}
}
});
if(!this.ogl.db.options.ignoreConsumption) total.deut -= (Object.values(data)?.[0]?.conso || 0);
total.msu = Util.getMSU(total.metal, total.crystal, total.deut, this.ogl.db.options.msu) || 0;
const start = new Date(this.displayedRange.start).toLocaleString('default', { day:'numeric', month:'long', year:'numeric' });
const end = new Date(this.displayedRange.end).toLocaleString('default', { day:'numeric', month:'long', year:'numeric' });
total.title = start == end ? start : `${start}➜<br>${end}`;
this.ogl._dom.updateMiniStats(total);
}
// turn db key date ('2024-7-9') into valid date keys ('2024-07-09')
// fix for iOS / OSX
normalizeDateKey(dateKey)
{
return dateKey.replace(/\b(\d)\b/g, '0$1');
}
// compare two keys : a > b = 1 | a == b = 0 | a < b = -1
compareDateKey(dateKeyA, dateKeyB)
{
return this.normalizeDateKey(dateKeyA).localeCompare(this.normalizeDateKey(dateKeyB));
}
filterStatsByDateRange(startKey, endKey)
{
endKey = endKey || startKey;
const data = this.ogl.db.stats;
const serverTimeKey = this.ogl._time.timeToKey(serverTime.getTime());
this.displayedRange.start = this.compareDateKey(serverTimeKey, startKey) > 0 ? startKey : serverTimeKey;
this.displayedRange.end = this.compareDateKey(serverTimeKey, endKey) > 0 ? endKey : serverTimeKey;
const filtered = Object.keys(data).filter(key =>
{
return this.compareDateKey(key, this.displayedRange.start) >= 0 && this.compareDateKey(key, this.displayedRange.end) <= 0;
}).reduce((result, key) =>
{
result[key] = data[key];
return result;
}, {});
return filtered;
}
getTotalFiltered(data)
{
const total = {};
for(const key in data)
{
const entry = data[key];
for(const prop in entry)
{
if(typeof entry[prop] === "number") // cumul int values
{
total[prop] = (total[prop] || 0) + entry[prop];
}
else if (Array.isArray(entry[prop])) // merge arrays
{
total[prop] = [...new Set([...(total[prop] || []), ...entry[prop]])];
}
else if (typeof entry[prop] === "object" && entry[prop] !== null) // merge objects recursively
{
total[prop] = this.getTotalFiltered([entry[prop], total[prop] || {}]);
}
}
}
return total;
}
getDayStats(dateKey)
{
const [year, month, day] = dateKey.split('-');
dateKey = `${year}-${parseInt(month)}-${parseInt(day)}`; // 2024-07-12 -> 2024-7-12
this.ogl.db.stats[dateKey] = this.ogl.db.stats[dateKey] || {};
return this.ogl.db.stats[dateKey];
}
getDaysInDisplayedMonth(dateKey)
{
dateKey = dateKey || this.displayedRange.end;
const end = new Date(dateKey);
const year = end.getFullYear();
const month = end.getMonth();
return new Date(year, month + 1, 0).getDate();
}
getTotalDaysInFilteredRange()
{
const start = new Date(this.displayedRange.start);
const end = new Date(this.displayedRange.end);
const timeDifference = end - start;
return Math.ceil(timeDifference / (1000 * 60 * 60 * 24)) + 1;
}
showDetails()
{
const dataByDay = this.filterStatsByDateRange(this.displayedRange.start, this.displayedRange.end);
const dataTotal = this.getTotalFiltered(Object.values(dataByDay));
const daysInDisplayedMonth = this.getDaysInDisplayedMonth();
const container = Util.addDom('div', { class:'ogl_stats' });
const month = Util.addDom('div', { parent:container, class:'ogl_statsMonth' });
const dateBar = Util.addDom('div', { parent:container, class:'ogl_dateBar' });
const details = Util.addDom('div', { parent:container, class:'ogl_statsDetails' });
const title = Util.addDom('h3', { child:'date', parent:details });
const pie = Util.addDom('div', { class:'ogl_pie', parent:details });
const shipTable = Util.addDom('div', { parent:details, class:'ogl_shipTable' });
const sumTable = Util.addDom('div', { parent:details, class:'ogl_sumTable' });
const displayed = this.displayedRange.end.split('-');
const now = this.ogl._time.timeToKey(serverTime.getTime());
let highest = 0, lowest = 0;
// day bars
for(let i=1; i<=daysInDisplayedMonth; i++)
{
const dateString = `${displayed[0]}-${displayed[1].toString().padStart(2, '0')}-${i.toString().padStart(2, '0')}`;
const dataMonth = this.ogl.db.stats[`${displayed[0]}-${parseInt(displayed[1])}-${i}`];
let metal = 0, crystal = 0, deut = 0;
['expe', 'debris', 'raid', 'debris16'].forEach(key =>
{
for(let [gainID, value] of Object.entries(dataMonth?.[key]?.gain || {}))
{
if(!isNaN(gainID))
{
const shipData = Datafinder.getTech(Math.abs(gainID));
const shipFactor = key == 'expe' && parseInt(gainID) > 0 ? this.ogl.db.options.expeditionShipRatio / 100 : 1;
const sign = parseInt(gainID) > 0 ? 1 : -1;
const isIgnored = sign < 0 && key == 'expe' && this.ogl.db.options.ignoreExpeShipsLoss;
if(!isIgnored)
{
metal += ((shipData.metal || 0) * value * shipFactor * sign);
crystal += ((shipData.crystal || 0) * value * shipFactor * sign);
deut += ((shipData.deut || 0) * value * shipFactor * sign);
}
}
else
{
if(gainID == 'metal') metal += (value || 0);
else if (gainID == 'crystal') crystal += (value || 0);
else if (gainID == 'deut') deut += (value || 0);
}
}
});
if(!this.ogl.db.options.ignoreConsumption) deut -= (dataMonth?.conso || 0);
const totalMSU = Util.getMSU(metal, crystal, deut, this.ogl.db.options.msu) || 0;
if(totalMSU < lowest) lowest = totalMSU;
if(totalMSU > highest) highest = totalMSU;
const item = Util.addDom('div', { class:'ogl_item', parent:dateBar, 'data-day':i, 'data-date':dateString, 'data-value':totalMSU });
if(dateString == now) item.classList.add('ogl_today');
}
this.addButtons(month);
this.updateTitle(title);
this.updatePie(pie, dataTotal);
this.updateShips(shipTable, dataTotal);
this.updateRecap(sumTable, dataTotal);
this.initRangeSelection(dateBar, lowest, highest);
this.ogl._popup.open(container, true);
}
addButtons(container)
{
container.innerText = '';
// filter today
Util.addDom('div', { parent:container, class:'ogl_button', child:LocalizationStrings?.timeunits?.short?.day || 'D', onclick:() =>
{
this.displayedRange = { start:this.ogl._time.timeToKey(serverTime.getTime()), end:this.ogl._time.timeToKey(serverTime.getTime()) };
this.showDetails();
}});
// filter current week
Util.addDom('div', { parent:container, class:'ogl_button', child:LocalizationStrings?.timeunits?.short?.week || 'W', onclick:() =>
{
const now = serverTime;
const startDate = this.ogl._time.timeToKey(new Date(now.setDate(now.getDate() - now.getDay() + 1)));
const endDate = this.ogl._time.timeToKey(new Date(now.setDate(now.getDate() + 7 - now.getDay())));
this.displayedRange.start = startDate;
this.displayedRange.end = endDate;
this.showDetails();
}});
// filter current month
Util.addDom('div', { parent:container, class:'ogl_button', child:LocalizationStrings?.timeunits?.short?.month || 'M', onclick:() =>
{
const now = serverTime;
const month = (now.getMonth() + 1).toString().padStart(2, '0');
const year = now.getFullYear();
const start = `${year}-${month}-01`;
const end = `${year}-${month}-${this.getDaysInDisplayedMonth(start).toString().padStart(2, '0')}`;
this.displayedRange.start = start;
this.displayedRange.end = end;
this.showDetails();
}});
Util.addDom('div', { parent:container, class:'ogl_button', child:'All', onclick:() =>
{
const oldestEntry = Object.keys(this.ogl.db.stats).reduce((oldestKey, currentKey) =>
{
return this.compareDateKey(currentKey, oldestKey) <= 0 ? currentKey : oldestKey;
});
this.displayedRange = { start:this.normalizeDateKey(oldestEntry), end:this.ogl._time.timeToKey(serverTime.getTime()) };
this.showDetails();
}});
Util.addDom('div', { parent:container, class:'ogl_separator' });
Util.addDom('div', { parent:container, class:'ogl_button material-icons', child:'keyboard_arrow_left', onclick:() =>
{
const start = new Date(this.displayedRange.end);
const previousMonth = start.getMonth() === 0 ? 11 : start.getMonth() - 1;
const year = start.getMonth() === 0 ? start.getFullYear() - 1 : start.getFullYear();
const formattedMonth = (previousMonth + 1).toString().padStart(2, '0');
const startPrevMonth = `${year}-${formattedMonth}-01`;
const endPrevMonth = `${year}-${formattedMonth}-${this.getDaysInDisplayedMonth(startPrevMonth).toString().padStart(2, '0')}`;
this.displayedRange.start = startPrevMonth;
this.displayedRange.end = endPrevMonth;
this.showDetails();
}});
Util.addDom('div', { parent:container, child:new Date(this.displayedRange.end).toLocaleString('default', { month:'short', year:'numeric' }) });
Util.addDom('div', { parent:container, class:'ogl_button material-icons', child:'keyboard_arrow_right', onclick:() =>
{
const start = new Date(this.displayedRange.end);
const nextMonth = start.getMonth() === 11 ? 0 : start.getMonth() + 1;
const year = start.getMonth() === 11 ? start.getFullYear() + 1 : start.getFullYear();
const now = serverTime;
if(nextMonth > now.getMonth() && year >= now.getFullYear()) return null;
const formattedMonth = (nextMonth + 1).toString().padStart(2, '0');
const startNextMonth = `${year}-${formattedMonth}-01`;
const endNextMonth = `${year}-${formattedMonth}-${this.getDaysInDisplayedMonth(startNextMonth).toString().padStart(2, '0')}`;
this.displayedRange.start = startNextMonth;
this.displayedRange.end = endNextMonth;
this.showDetails();
}});
}
initRangeSelection(bars, lowest, highest)
{
let isSelecting = false;
let startDate = null;
let endDate = null;
bars.querySelectorAll('.ogl_item').forEach(bar =>
{
const value = parseInt(bar.getAttribute('data-value'));
let height = Math.ceil(Math.abs(value) / (Math.max(Math.abs(highest), Math.abs(lowest)) / 100));
height = height > 0 ? Math.max(height, 5) : 0;
const color = value > 0 ? '#35cf95' : '#e14848';
const content = Util.addDom('div', { parent:bar });
content.style.background = `linear-gradient(to top, ${color} ${height}%, #0e1116 ${height}%)`;
if(value != 0) bar.classList.add('ogl_active');
});
bars.addEventListener('mousedown', e =>
{
if(e.target.classList.contains('ogl_item') && e.button === 0)
{
isSelecting = true;
startDate = e.target.dataset.date;
endDate = startDate;
}
});
bars.addEventListener('mouseover', e =>
{
if(isSelecting && e.target.classList.contains('ogl_item'))
{
endDate = e.target.dataset.date;
this.highlightRange(bars, startDate, endDate);
}
});
bars.addEventListener('mouseup', e =>
{
if(isSelecting)
{
isSelecting = false;
this.displayedRange.start = this.compareDateKey(startDate, endDate) <= 0 ? startDate : endDate;
this.displayedRange.end = this.compareDateKey(startDate, endDate) <= 0 ? endDate : startDate;
this.showDetails();
}
});
this.highlightRange(bars, this.displayedRange.start, this.displayedRange.end);
}
highlightRange(bars, startDate, endDate)
{
bars.querySelectorAll('.ogl_item').forEach(bar =>
{
const date = bar.dataset.date;
if((this.compareDateKey(date, startDate) >= 0 && this.compareDateKey(date, endDate) <= 0) || (this.compareDateKey(date, endDate) >= 0 && this.compareDateKey(date, startDate) <= 0)) bar.classList.add('ogl_selected');
else bar.classList.remove('ogl_selected');
});
}
updateTitle(container)
{
const startText = new Date(this.displayedRange.start).toLocaleString('default', { day:'numeric', month:'long', year:'numeric' });
const endText = new Date(this.displayedRange.end).toLocaleString('default', { day:'numeric', month:'long', year:'numeric' });
const rangeText = this.displayedRange.start == this.displayedRange.end ? startText : `${startText} <i class="material-icons">east</i> ${endText}`;
container.innerHTML = rangeText;
const icons = Util.addDom('div', { class:'ogl_statsSettingsIcons', parent:container });
Util.addDom('div', { class:this.ogl.db.options.ignoreConsumption ? 'material-icons tooltip ogl_active ogl_bool' : 'material-icons tooltip ogl_bool', child:'local_gas_station', title:'Consumption', parent:icons, });
Util.addDom('div', { class:this.ogl.db.options.ignoreExpeShipsLoss ? 'material-icons tooltip ogl_active ogl_bool' : 'material-icons tooltip ogl_bool', child:'skull', title:'Ships lost in expedition', parent:icons });
Util.addDom('div', { class:'tooltip', child:`<i class="material-icons">rocket</i><span>${this.ogl.db.options.expeditionShipRatio || 0}%</span>`, title:this.ogl._lang.find('expeditionShipRatio'), parent:icons });
}
updateShips(container, data)
{
container.innerText = '';
[202,203,204,205,206,207,208,209,210,211,213,214,215,218,219].forEach(shipId =>
{
const expe = (data?.expe?.gain?.[shipId] || 0) - (data?.expe?.gain?.[-shipId] || 0);
const raid = (data?.raid?.gain?.[shipId] || 0) - (data?.raid?.gain?.[-shipId] || 0);
const total = expe + raid;
Util.addDom('div', { class:`ogl_icon ogl_${shipId} tooltip`, title:`<div class="ogl_infoStats"><h3 class="ogl_textCenter">${this.ogl._lang.find(shipId)}</h3><hr>Expeditions: <b>${Util.formatNumber(expe)}</b><br>Raids: <b>${Util.formatNumber(raid)}</b></div>`, parent:container, child:Util.formatToUnits(total || '-', false, true) });
});
}
updatePie(container, data)
{
container.innerText = '';
const occurences = data?.expe?.occurence;
if(!occurences)
{
container.innerHTML = '<div class="ogl_noExpe"><span class="material-icons">compass</span>No expedition data</div>';
return;
}
let cumulAngle = 1.5 * Math.PI;
let colors =
{
nothing:'#ddd',
resource:'#86edfd',
darkmatter:'#b58cdb',
ship:'#1dd1a1',
battle:'#ffd60b',
item:'#bf6c4d',
blackhole:'#818181',
duration:'#df5252',
trader:'#ff7d30',
}
const pieData = {};
pieData.resource = occurences.resource || 0;
pieData.darkmatter = occurences.darkmatter || 0;
pieData.ship = occurences.ship || 0;
pieData.nothing = occurences.nothing || 0;
pieData.blackhole = occurences.blackhole || 0;
pieData.trader = occurences.trader || 0;
pieData.item = occurences.item || 0;
pieData.battle = (occurences.pirate || 0) + (occurences.alien || 0);
pieData.duration = (occurences.early || 0) + (occurences.late || 0);
const size = 256;
const center = size / 2;
const radius = size / 2;
const slices = [];
const drawPie = hoveredSlice =>
{
ctx.clearRect(0, 0, size, size);
slices.forEach(slice =>
{
ctx.beginPath();
ctx.arc(center, center, radius, slice.startAngle, slice.endAngle);
ctx.lineTo(center, center);
ctx.closePath();
ctx.fillStyle = slice.title == hoveredSlice?.title ? 'white' : slice.color;
ctx.fill();
});
// donut
ctx.fillStyle = "rgba(0,0,0,.5)";
ctx.beginPath();
ctx.arc(size/2, size/2, size/2.7, 0, 2 * Math.PI, false);
ctx.fill();
ctx.fillStyle = "#1b212a";
ctx.beginPath();
ctx.arc(size/2, size/2, size/3, 0, 2 * Math.PI, false);
ctx.fill();
container.setAttribute('data-pie', `${hoveredSlice ? this.ogl._lang.find(hoveredSlice.title) + '\r\n' : ''}${hoveredSlice ? hoveredSlice.percent + '%' : total + '\r\nExpeditions'}`);
legend.querySelectorAll('.ogl_active').forEach(e => e.classList.remove('ogl_active'));
if(hoveredSlice)
{
legend.querySelector(`[data-entry="${hoveredSlice.title}"]`).classList.add('ogl_active');
}
}
const canvas = Util.addDom('canvas', { parent:container, width:size, height:size, onmouseout:() => { drawPie();canvas.classList.remove('ogl_interactive'); }});
const ctx = canvas.getContext('2d', { willReadFrequently:true });
const legend = Util.addDom('div', { parent:container, class:'ogl_pieLegendContainer', onmouseleave:() => drawPie() });
const dataArray = Object.entries(pieData || {});
const total = Object.values(occurences || {}).reduce((accumulator, e) => accumulator + Math.max(0, e), 0);
container.setAttribute('data-pie', total);
for(let [title, value] of dataArray.sort((a, b) => b[1] - a[1]))
{
if(value > 0)
{
const slice = {};
slice.title = title;
slice.value = value;
slice.percent = (value / total * 100).toFixed(2);
slice.startAngle = cumulAngle;
slice.angle = (value / total) * 2 * Math.PI;
slice.endAngle = cumulAngle + slice.angle;
slice.color = colors[title];
slices.push(slice);
cumulAngle = slice.endAngle;
Util.addDom('div', { class:'ogl_pieLegend', 'data-resultType':slice.title, 'data-entry':slice.title, parent:legend, child:`<div>${this.ogl._lang.find(title)}</div><span>${Util.formatToUnits(value)}</span><i>${slice.percent}%</i>` });
}
}
drawPie();
legend.querySelectorAll('.ogl_pieLegend').forEach(line =>
{
line.addEventListener('mouseenter', () =>
{
const slice = slices.find(slice => slice.title == line.getAttribute('data-entry'));
drawPie(slice);
});
});
}
updateRecap(container, data)
{
container.innerText = '';
const typeLong = { expe:'expeditions', raid:'raids', conso:'consumption', u:'average', total:'total' };
const header = Util.addDom('div', { parent:container });
['', 'send', 'metal', 'crystal', 'deut', 'msu', 'dm', 'artefact'].forEach(resource =>
{
if(resource == 'send') Util.addDom('div', { class:`ogl_textCenter ogl_icon material-icons`, child:'send', parent:header });
else Util.addDom('div', { class:`ogl_icon ogl_${resource}`, parent:header });
});
['expe', 'raid', 'conso', 'u', 'total'].forEach(type =>
{
const line = Util.addDom('div', { parent:container, child:`<div class="ogl_statsRecapHeader">${typeLong[type]}</div>` });
const missions = Util.addDom('div', { parent:line, class:'tooltip' });
let missionsCount = 0;
let missionsDetail = Util.addDom('div', { class:'ogl_infoStats' });
let metal = 0, crystal = 0, deut = 0, dm = 0, artefact = 0;
let dataKeys = [];
if(type == 'expe') dataKeys = ['expe', 'debris16'];
else if(type == 'raid') dataKeys = ['raid', 'debris'];
else if(type == 'total' || type == 'u') dataKeys = ['expe', 'debris16', 'raid', 'debris', 'discovery'];
dataKeys.forEach(key =>
{
if(key == 'discovery' && type == 'u') Util.addDom('div', { parent:missionsDetail, child:'<hr>' });
else missionsCount += (data?.[key]?.count || 0);
Util.addDom('div', { parent:missionsDetail, child:`${key}: <b>${Util.formatNumber(data?.[key]?.count || 0)}</b>` });
for(let [gainID, value] of Object.entries(data?.[key]?.gain || {}))
{
if(!isNaN(gainID))
{
const shipData = Datafinder.getTech(Math.abs(gainID));
const shipFactor = key == 'expe' && parseInt(gainID) > 0 ? this.ogl.db.options.expeditionShipRatio / 100 : 1;
const sign = parseInt(gainID) > 0 ? 1 : -1;
const isIgnored = sign < 0 && key == 'expe' && this.ogl.db.options.ignoreExpeShipsLoss;
if(!isIgnored)
{
metal += ((shipData.metal || 0) * value * shipFactor * sign);
crystal += ((shipData.crystal || 0) * value * shipFactor * sign);
deut += ((shipData.deut || 0) * value * shipFactor * sign);
}
}
else
{
if(gainID == 'metal') metal += (value || 0);
else if (gainID == 'crystal') crystal += (value || 0);
else if (gainID == 'deut') deut += (value || 0);
else if (gainID == 'dm') dm += (value || 0);
else if (gainID == 'artefact') artefact += (value || 0);
}
}
});
if(type == 'expe' || type == 'raid')
{
Util.addDom('div', { parent:line, class:'ogl_metal', child:Util.formatToUnits(metal, false, true) });
Util.addDom('div', { parent:line, class:'ogl_crystal', child:Util.formatToUnits(crystal, false, true) });
Util.addDom('div', { parent:line, class:'ogl_deut', child:Util.formatToUnits(deut, false, true) });
Util.addDom('div', { parent:line, class:'ogl_msu', child:Util.formatToUnits(Util.getMSU(metal, crystal, deut, this.ogl.db.options.msu), false, true) });
Util.addDom('div', { parent:line, class:'ogl_dm', child:type == 'raid' ? '-' : Util.formatToUnits(dm, false, true) });
Util.addDom('div', { parent:line, class:'ogl_artefact', child:'-' });
}
else if(type == 'u')
{
if(!this.ogl.db.options.ignoreConsumption) deut -= (data.conso || 0);
Util.addDom('div', { parent:line, class:'ogl_metal', child:!missionsCount ? 0 : Util.formatToUnits(Math.floor(metal / missionsCount), false, true) });
Util.addDom('div', { parent:line, class:'ogl_crystal', child:!missionsCount ? 0 : Util.formatToUnits(Math.floor(crystal / missionsCount), false, true) });
Util.addDom('div', { parent:line, class:'ogl_deut', child:!missionsCount ? 0 : Util.formatToUnits(Math.floor(deut / missionsCount), false, true) });
Util.addDom('div', { parent:line, class:'ogl_msu', child:!missionsCount ? 0 : Util.formatToUnits(Util.getMSU(metal, crystal, deut, this.ogl.db.options.msu) / missionsCount, false, true) });
Util.addDom('div', { parent:line, class:'ogl_dm', child:!data?.expe?.count ? 0 : Util.formatToUnits(Math.floor(dm / data?.expe?.count), false, true) });
Util.addDom('div', { parent:line, class:'ogl_artefact', child:!data?.discovery?.count ? 0 : Util.formatToUnits(Math.floor(artefact / data?.discovery?.count), false, true) });
}
else if(type == 'conso')
{
Util.addDom('div', { parent:line, class:'ogl_metal', child:'-' });
Util.addDom('div', { parent:line, class:'ogl_crystal', child:'-' });
Util.addDom('div', { parent:line, class:'ogl_deut', child:Util.formatToUnits(-data.conso, false, true) });
Util.addDom('div', { parent:line, class:'ogl_msu', child:Util.formatToUnits(Util.getMSU(0, 0, -data.conso, this.ogl.db.options.msu), false, true) });
Util.addDom('div', { parent:line, class:'ogl_dm', child:'-' });
Util.addDom('div', { parent:line, class:'ogl_artefact', child:'-' });
}
else if(type == 'total')
{
if(!this.ogl.db.options.ignoreConsumption) deut -= (data.conso || 0);
Util.addDom('div', { parent:line, class:'ogl_metal', child:Util.formatToUnits(metal, false, true) });
Util.addDom('div', { parent:line, class:'ogl_crystal', child:Util.formatToUnits(crystal, false, true) });
Util.addDom('div', { parent:line, class:'ogl_deut', child:Util.formatToUnits(deut, false, true) });
Util.addDom('div', { parent:line, class:'ogl_msu', child:Util.formatToUnits(Util.getMSU(metal, crystal, deut, this.ogl.db.options.msu), false, true) });
Util.addDom('div', { parent:line, class:'ogl_dm', child:Util.formatToUnits(dm, false, true) });
Util.addDom('div', { parent:line, class:'ogl_artefact', child:Util.formatToUnits(artefact, false, true) });
}
missions.innerHTML = missionsCount == 0 ? '-' : Util.formatToUnits(missionsCount, false, true);
if(missionsCount) missions.title = missionsDetail.outerHTML;
});
}
}
class EmpireManager extends Manager
{
load()
{
this.getLFBonuses();
this.getAllianceClass();
if(this.ogl.page != 'empire') return;
unsafeWindow.jumpGateLink = `https://${window.location.host}/game/index.php?page=ajax&component=jumpgate&overlay=1&ajax=1`;
unsafeWindow.jumpGateLoca = { LOCA_STATION_JUMPGATE_HEADLINE: 'Jumpgate' };
let updateDone = false;
let planetData, planetName;
Util.observe(document.body, {childList:true, subtree:true, attributes:true}, mutation =>
{
if(!updateDone && mutation.target.classList.contains('box-end') && mutation.target.closest('.summary') && mutation.target.closest('.groupresources'))
{
if(document.querySelector('#loading').style.display == 'none')
{
updateDone = true;
this.update(document.querySelector('#mainContent script').innerText, new URLSearchParams(window.location.search).get('planetType'), true);
document.querySelectorAll('.planet').forEach(planet =>
{
const data = this.ogl.db.myPlanets[planet.id.replace('planet', '')];
if(!data) return;
Util.addDom('div', { class:'material-icons ogl_empireJumpgate', child:'jump_to_element', parent:planet.querySelectorAll('.row')[1], onclick:e =>
{
e.preventDefault();
planetData = data;
planetName = planet.querySelector('.planetname').getAttribute('title') || planet.querySelector('.planetname').innerText;
document.querySelector('.ui-dialog')?.remove();
setTimeout(() => openJumpgate(), 5);
}});
});
}
}
else if(mutation.target.classList.contains('ui-dialog') && document.querySelector('#jumpgate'))
{
if(document.querySelector('#jumpgateNotReady')) return;
if(document.querySelector('.currentlySelected'))
{
const target = document.querySelector('.currentlySelected a');
target.setAttribute('data-value', planetData.planetID || planetData.moonID);
target.innerText = `${planetName} [${planetData.coords}]`;
}
else
{
document.querySelector('#selecttarget select').value = this.ogl.db.myPlanets[planetData.planetID].moonID;
}
let resources = [planetData.metal, planetData.crystal, planetData.deut, planetData.food];
if(this.ogl.db.fleetLimiter.resourceActive)
{
resources[0] = Math.max(0, resources[0] - (this.ogl.db.fleetLimiter.data.metal || 0));
resources[1] = Math.max(0, resources[1] - (this.ogl.db.fleetLimiter.data.crystal || 0));
resources[2] = Math.max(0, resources[2] - (this.ogl.db.fleetLimiter.data.deut || 0));
resources[3] = Math.max(0, resources[3] - (this.ogl.db.fleetLimiter.data.food || 0));
}
const total = resources[0] + resources[1] + resources[2] + resources[3];
document.querySelector(`[name="ship_${this.ogl.db.options.defaultShip}"]`).value = this.ogl._fleet.shipsForResources(this.ogl.db.options.defaultShip, Math.max(0, total));
}
});
}
update(data, type, fromEmpire)
{
this.ogl.db[`lastEmpire${type}Update`] = Date.now();
let allowedEntries = ['id', 'metal', 'crystal', 'deuterium', 'energy', 'food', 'population', 'fieldUsed', 'fieldMax', 'planetID', 'moonID'];
data = fromEmpire ? JSON.parse(data.match(/{(.*)}/g)[1]) : data;
data.planets?.forEach(planet =>
{
this.ogl.db.myPlanets[planet.id] = this.ogl.db.myPlanets[planet.id] || {};
this.ogl.db.myPlanets[planet.id].type = type === 0 ? 'planet' : 'moon';
Object.entries(planet).forEach(entry =>
{
if(entry[0].indexOf('html') >= 0) return;
else if(entry[0] === 'temperature') this.ogl.db.myPlanets[planet.id][entry[0]] = parseInt(entry[1].match(/[-|0-9]+/g, '' )[0]);
else if(Number(entry[0]) || entry[0].indexOf('Storage') >= 0 || allowedEntries.includes(entry[0])) this.ogl.db.myPlanets[planet.id][entry[0].replace('deuterium', 'deut')] = parseInt(entry[1]);
else if(entry[0] === 'coordinates') this.ogl.db.myPlanets[planet.id].coords = entry[1].slice(1, -1);
else if(entry[0] === 'production')
{
this.ogl.db.myPlanets[planet.id].prodMetal = entry[1].hourly[0] / 3600;
this.ogl.db.myPlanets[planet.id].prodCrystal = entry[1].hourly[1] / 3600;
this.ogl.db.myPlanets[planet.id].prodDeut = entry[1].hourly[2] / 3600;
}
});
});
if(this.ogl.currentPlanet) this.ogl.currentPlanet.obj = this.ogl.db.myPlanets[document.querySelector('head meta[name="ogame-planet-id"]')?.getAttribute('content')];
if(!fromEmpire)
{
this.ogl._dom.updateAvailable();
this.ogl._dom.updatePlanetTimers();
}
if(this.ogl._ui) Util.runAsync(() => this.ogl._ui.displayResourcesRecap());
}
getLFBonuses(source)
{
const htmlSource = source || document;
// lf bonuses
if(source || this.ogl.page == 'lfbonuses')
{
this.ogl.db.lfBonuses = {};
htmlSource.querySelectorAll('bonus-item-content-holder > [data-toggable]').forEach(item =>
{
const id = item.getAttribute('data-toggable').replace(/subcategory|Ships|Defenses|CostAndTime/g, '');
const regex = new RegExp(`[0-9|-]+(${LocalizationStrings.decimalPoint}[0-9]+)?`, 'g');
const isBaseBuilding = id < 100;
const isBaseResearch = id > 100 && id <= 199;
const isBaseShip = id > 200 && id <= 299;
const isBaseDef = id > 400 && id <= 499;
const lfBonuses = {};
const bonuses = []; // bonuses [0]:value, [1]:max
item.querySelectorAll('bonus-item').forEach(bonus =>
{
const values = (bonus.innerText.match(regex) || []).map(e =>
{
if(e == '-') return 0;
else return parseFloat(e.replace(LocalizationStrings.decimalPoint, '.'));
});
bonuses.push(values);
});
if(bonuses.length == 0)
{
let value = (item.innerText.match(regex) || [])[0];
if(!value || value == '-') value = 0;
else value = parseFloat(value.replace(LocalizationStrings.decimalPoint, '.'));
lfBonuses.bonus = value;
}
if(isBaseShip)
{
lfBonuses.armor = bonuses[0][0];
lfBonuses.shield = bonuses[1][0];
lfBonuses.weapon = bonuses[2][0];
lfBonuses.speed = bonuses[3][0];
lfBonuses.cargo = bonuses[4][0];
lfBonuses.fuel = bonuses[5][0];
}
else if(isBaseDef)
{
lfBonuses.armor = bonuses[0][0];
lfBonuses.shield = bonuses[1][0];
lfBonuses.weapon = bonuses[2][0];
}
else if(isBaseResearch || id == 'LfResearch')
{
lfBonuses.cost = bonuses[0][0];
lfBonuses.duration = bonuses[1][0];
}
if(id == 'MiscImprovedCrawler')
{
lfBonuses.bonus = bonuses[1][0];
}
this.ogl.db.lfBonuses[id] = lfBonuses;
});
}
// race level
if(source || this.ogl.page == 'lfbonuses' || this.ogl.page == 'lfsettings')
{
this.ogl.db.lfBonuses = this.ogl.db.lfBonuses || {};
htmlSource.querySelectorAll('lifeform-item, .lifeform-item').forEach(item =>
{
const lifeform = item.querySelector('.lifeform-item-icon').className.replace(/lifeform-item-icon| /g, '');
const bonus = item.querySelector('.currentlevel').innerText.replace(/\D/g, '') / 10;
this.ogl.db.lfBonuses[lifeform] = { bonus:bonus };
});
}
}
getAllianceClass()
{
if(this.ogl.page == 'alliance')
{
setTimeout(() =>
{
const sprite = alliance.allianceContent[0].querySelector('#allyData .allianceclass.sprite');
if(!sprite)
{
this.getAllianceClass();
}
else
{
const className = (Array.from(sprite.classList).filter(element => allianceClassArr.includes(element)) || ['neutral'])[0];
const classID = allianceClassArr.indexOf(className);
this.ogl.db.allianceClass = classID >= 0 ? classID : 0;
}
}, 1000);
}
}
}
class Util
{
static get simList()
{
return {
battlesim:'https://battlesim.logserver.net/',
'simulator.ogame-tools':'https://simulator.ogame-tools.com/',
}
}
static get converterList()
{
return {
ogotcha:'https://ogotcha.oplanet.eu/',
topraider:'https://topraider.eu/index.php',
'ogame.tools':'https://battleconvertor.fr',
}
}
static overWrite(fn, context, before, after, newParam1, newParam2)
{
const old = context[fn];
let locked = false;
context[fn] = function(param1, param2)
{
if(before && typeof before === typeof function(){}) locked = before(newParam1 || param1, newParam2 || param2);
if(!locked) old.call(context, newParam1 || param1, newParam2 || param2);
if(after && typeof after === typeof function(){} && !locked) after(newParam1 || param1, newParam2 || param2);
}
}
static drawLine(svg, parent, element1, element2)
{
if(unsafeWindow.fleetDispatcher && fleetDispatcher.realTarget
&& (fleetDispatcher.targetPlanet.galaxy != fleetDispatcher.realTarget.galaxy
|| fleetDispatcher.targetPlanet.system != fleetDispatcher.realTarget.system
|| fleetDispatcher.targetPlanet.position != fleetDispatcher.realTarget.position
|| fleetDispatcher.targetPlanet.type != fleetDispatcher.realTarget.type)) return;
svg.querySelector('line')?.remove();
if(!element1 || !element2 || element1 == element2) return;
element1 = element1.querySelector('.planetPic, .icon-moon');
element2 = element2.querySelector('.planetPic, .icon-moon');
let x1 = Math.round(element1.getBoundingClientRect().left + element1.getBoundingClientRect().width / 2 - parent.getBoundingClientRect().left) - 2;
let y1 = Math.round(element1.getBoundingClientRect().top + element1.getBoundingClientRect().height / 2 - parent.getBoundingClientRect().top);
let x2 = Math.round(element2.getBoundingClientRect().left + element2.getBoundingClientRect().width / 2 - parent.getBoundingClientRect().left) - 2;
let y2 = Math.round(element2.getBoundingClientRect().top + element2.getBoundingClientRect().height / 2 - parent.getBoundingClientRect().top);
parent.appendChild(svg);
let line = document.createElementNS('http://www.w3.org/2000/svg','line');
svg.appendChild(line);
line.classList.add('ogl_line');
line.setAttribute('x1',x1);
line.setAttribute('y1',y1);
line.setAttribute('x2',x2);
line.setAttribute('y2',y2);
line.setAttribute('stroke-dasharray', '7 5');
}
static coordsToID(arr)
{
if(typeof arr === typeof '') return arr.split(':').map(x => x.padStart(3, '0')).join('');
else return arr.map(x => x.padStart(3, '0')).join('');
}
static removeFromArray(arr, index)
{
arr.splice(index, 1);
}
static formatNumber(number, fixed)
{
number = number || 0;
if(fixed)
{
number = number % 1 === 0 ? number : number.toFixed(fixed);
}
return number.toLocaleString('de-DE');
}
static formatToUnits(value, forced, colored)
{
value = Math.round(value || 0);
value = (value || 0).toString().replace(/[\,\. ]/g, '');
if(isNaN(value)) return value;
let precision = 0;
value = parseInt(value);
if(value == 0 || forced === 0 || (value < 1000 && value > -1000)) precision = 0;
else if(forced === 1 || (value < 1000000 && value > -1000000)) precision = 1;
else precision = 2;
const split = Intl.NumberFormat('fr-FR', { notation:'compact', minimumFractionDigits:precision, maximumFractionDigits:precision }).format(value).match(/[a-zA-Z]+|[0-9,-]+/g);
const result = split[0].replace(/,/g, '.');
const suffix = split[1]?.replace('Md', 'G').replace('Bn', 'T') || '';
const resultDom = Util.addDom('span', { class:'ogl_unit', child:`<span>${result}</span><span class="ogl_suffix">${suffix}</span>` });
if(value < 0 && colored) resultDom.classList.add('ogl_danger');
return resultDom.outerHTML;
}
static formatFromUnits(value)
{
if(!value) return 0;
value = value.toLowerCase();
let offset = (value.split(LocalizationStrings.thousandSeperator).length - 1) * 3;
if(LocalizationStrings.thousandSeperator == LocalizationStrings.decimalPoint) offset = 0;
let splitted = value.match(/\d+/g)[0].length;
if(value.indexOf(LocalizationStrings.unitMilliard.toLowerCase()) > -1)
{
value = value.replace(LocalizationStrings.unitMilliard.toLowerCase(), '');
value = value.replace(/[\,\. ]/g, '');
value = value.padEnd(9 + offset + splitted, '0');
}
else if(value.indexOf(LocalizationStrings.unitMega.toLowerCase()) > -1)
{
value = value.replace(LocalizationStrings.unitMega.toLowerCase(), '');
value = value.replace(/[\,\. ]/g, '');
value = value.padEnd(6 + offset + splitted, '0');
}
else if(value.indexOf(LocalizationStrings.unitKilo.toLowerCase()) > -1)
{
value = value.replace(LocalizationStrings.unitKilo.toLowerCase(), '');
value = value.replace(/[\,\. ]/g, '');
value = value.padEnd(3 + offset + splitted, '0');
}
else
{
value = value.replace(/[\,\. ]/g, '');
}
return parseInt(value);
}
static formatInput(input, callback, canBeEmpty)
{
setTimeout(() =>
{
if((!input.value || input.value == 0) && input.classList.contains('ogl_placeholder'))
{
input.value = '';
return;
}
// firefox fix
input.value = input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
let oldLength = input.value.length;
let mult = 1;
if(input.value.toLowerCase().indexOf('k') >= 0) mult = 1000;
else if(input.value.toLowerCase().indexOf('m') >= 0) mult = 1000000;
else if(input.value.toLowerCase().indexOf('g') >= 0) mult = 1000000000;
let cursorPosition = input.selectionStart;
let formattedValue;
if(input.getAttribute('data-allowPercent') == 'true' && input.value.toLowerCase().indexOf('%') >= 0)
{
formattedValue = parseInt(input.value?.replace(/\D/g, '') || 0).toString();
formattedValue += '%';
}
else
{
formattedValue = (parseInt(input.value?.replace(/\D/g, '') || 0) * mult).toString();
formattedValue = formattedValue.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
input.value = formattedValue;
cursorPosition += input.value.length > oldLength ? 1 : input.value.length < oldLength ? -1 : 0;
input.setSelectionRange(cursorPosition, cursorPosition);
if(input.value == 0 && canBeEmpty) input.value = '';
if(callback) callback();
}, 5);
}
static reorderArray(arr, index, reversed)
{
let newArray = arr.slice(index, arr.length).concat(arr.slice(0, index));;
return reversed ? newArray.reverse() : newArray;
}
static observe(element, options, callback, oglObj)
{
options = options || {};
let tooltipTimeout;
let sendShipsTimeout;
new MutationObserver(mutations =>
{
if(oglObj && mutations[0].target.tagName.toLowerCase() !== 'progress')
{
Util.runAsync(oglObj._time.update, oglObj._time);
Util.runAsync(oglObj._time.observe, oglObj._time);
if(document.querySelector('[onclick*="sendShips(6"]:not([data-spy-coords]), [onclick*="sendShipsWithPopup(6"]:not([data-spy-coords])'))
{
Util.runAsync(oglObj._fleet.checkSendShips, oglObj._fleet);
}
}
for(let i=0; i<mutations.length; i++) callback(mutations[i]);
}).observe(element, options);
}
static addDom(tag, params)
{
params = params || {};
let element = document.createElement(tag);
element.classList.add('ogl_addedElement');
Object.entries(params).forEach(param =>
{
const isIgnored = param[0] === 'before' || param[0] === 'prepend' || param[0] === 'parent' || param[0] === 'after';
const isContent = param[0] === 'child';
const isListener = param[0].startsWith('on');
const isAttribute = !isContent && !isListener && !isIgnored;
if(isAttribute)
{
element.setAttribute(param[0], param[1]);
if(param[0] == 'class' && param[1].indexOf('material-icons') > -1) element.classList.add('notranslate');
}
else if(isListener)
{
element.addEventListener(param[0].toLowerCase().slice(2), event => {param[1](event, element)});
}
else if(isContent)
{
if(typeof param[1] === typeof {})
{
element.appendChild(param[1]);
}
else if(typeof param[1] === typeof '' || typeof param[1] === typeof 1)
{
element.innerHTML = param[1].toString();
}
}
});
if(params.parent) params.parent.appendChild(element);
else if(params.before) params.before.parentNode.insertBefore(element, params.before);
else if(params.after) params.after.after(element);
else if(params.prepend) params.prepend.prepend(element);
return element;
}
static runAsync(fn, scope)
{
return new Promise(resolve =>
{
setTimeout(() =>
{
resolve(scope ? scope[fn.toString().split('(')[0]]() : fn(scope));
});
});
}
static takeScreenshot(element, button, name, retry)
{
if(typeof html2canvas === 'undefined')
{
fetch('https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js', {method:'get', headers:{'Accept':'application/json'}})
.then(response => response.text())
.then(result =>
{
retry = (retry || 0) + 1;
if(retry > 3) return;
document.head.appendChild(Util.addDom('script', { type:'text/javascript', child:result }));
Util.takeScreenshot(element, button, name);
});
}
else
{
const rect = element.getBoundingClientRect();
html2canvas(element,
{
backgroundColor:null,
useCORS:true,
ignoreElements:e => e.classList.contains('ogl_close') || e.classList.contains('ogl_share'),
x:rect.x,
y:rect.y,
scrollX:0,
scrollY:0,
width:rect.width,
height:rect.height,
windowWidth:document.documentElement.offsetWidth,
windowHeight:document.documentElement.offsetHeight
}).then(canvas =>
{
const dataURL = canvas.toDataURL();
const link = Util.addDom('a', {'download':name, 'href':dataURL});
link.click();
button.classList.remove('ogl_disabled');
});
}
}
static hash(str)
{
return [...str].reduce((string, char) => Math.imul(31, string) + char.charCodeAt(0) | 0, 0);
}
static getMSU(metal, crystal, deut, ratio)
{
ratio = ratio.split(':');
return Math.ceil((metal || 0) + (crystal || 0) * ratio[0] / ratio[1] + (deut || 0) * ratio[0]);
}
static getPlayerScoreFD(score, type)
{
if(!score) return '?';
const defense = Math.max(score.military - (score.global - score.economy - score.research - score.lifeform), 0);
const fleet = score.military - defense;
return type == 'defense' ? defense : fleet;
}
static getDistance(ogl, from, to)
{
const emptySystems = ogl.db.serverData.emptySystems || false;
const inactiveSystems = ogl.db.serverData.inactiveSystems || false;
const donutGalaxy = ogl.db.serverData.donutGalaxy || false;
const donutSystem = ogl.db.serverData.donutSystem || false;
const maxGalaxy = ogl.db.serverData.galaxies || 9;
const maxSystem = ogl.db.serverData.systems || 499;
let diffGalaxy = Math.abs(from.galaxy - to.galaxy);
let diffSystem = Math.abs(from.system - to.system);
let diffPlanet = Math.abs(from.position - to.position);
if(diffGalaxy != 0)
{
let diff2 = Math.abs(diffGalaxy - maxGalaxy);
if(donutGalaxy && diff2 < diffGalaxy) return diff2 * 20000;
else return diffGalaxy * 20000;
}
else if (diffSystem != 0)
{
let diff2 = Math.abs(diffSystem - maxSystem);
let deltaSystem = 0;
if(donutSystem && diff2 < diffSystem) deltaSystem = diff2;
else deltaSystem = diffSystem;
deltaSystem = Math.max(deltaSystem - emptySystems - inactiveSystems, 1);
return deltaSystem * 5 * 19 + 2700;
}
else if (diffPlanet != 0)
{
return diffPlanet * 5 + 1000;
}
else
{
return 5;
}
}
static planetIsInRange(ogl, from, to, maxSystem)
{
const maxDistance = 2700 + 95 * maxSystem;
const distance = Util.getDistance(ogl, from, to);
return distance < maxDistance;
}
static genTrashsimLink(ogl, apiKey, data)
{
const attackerCoords = (data?.origin?.coords || ogl.currentPlanet.obj.coords).split(':');
const defenderCoords = (data?.destination?.coords || '0:0:0').split(':');
let jsonData = { settings:{ server:`s${ogl.server.id}-${ogl.server.lang}` } };
const player1 = // attacker
{
planet:
{
galaxy:attackerCoords[0],
system:attackerCoords[1],
position:attackerCoords[2],
},
research:{},
};
const player2 = // defender
{
planet:
{
galaxy:defenderCoords[0],
system:defenderCoords[1],
position:defenderCoords[2],
},
research:{},
resources:{},
defence:{},
};
// ################### me
const me = data?.meAsDefender ? player2 : player1;
me.class = ogl.account.class;
me.characterClassesEnabled = true;
me.allianceClass = ogl.db.allianceClass || 0;
[109, 110, 111, 114, 115, 117, 118].forEach(techID => me.research[techID] = { level:ogl.currentPlanet.obj[techID] || 0 });
let bonusBattleTechs = 0;
if(ogl.account.class == 2) // player general class +2 combat techs
{
bonusBattleTechs += 2;
// player general class 3.6 boost (50% = +1 level)
const classLFBoost = Math.floor((ogl.db.lfBonuses?.['Characterclasses'+ogl.account.class]?.bonus || 0) / 50);
bonusBattleTechs += classLFBoost;
}
if(ogl.db.allianceClass == 1) // alliance warrior class +1 combat techs
{
bonusBattleTechs++;
}
me.research[109].level = (me.research[109].level || 0) + bonusBattleTechs;
me.research[110].level = (me.research[110].level || 0) + bonusBattleTechs;
me.research[111].level = (me.research[111].level || 0) + bonusBattleTechs;
me.lifeformBonuses = me.lifeformBonuses || {};
me.lifeformBonuses.BaseStatsBooster = me.lifeformBonuses.BaseStatsBooster || {};
me.lifeformBonuses.CharacterClassBooster = {};
me.lifeformBonuses.CharacterClassBooster[ogl.account.class] = (ogl.db.lfBonuses?.['Characterclasses'+ogl.account.class]?.bonus || 0) / 100;
if(data?.meAsAttacker)
{
me.ships = data.ships;
}
ogl.shipsList.forEach(shipID =>
{
me.lifeformBonuses.BaseStatsBooster[shipID] = me.lifeformBonuses.BaseStatsBooster[shipID] || {};
Object.entries(ogl.db.lfBonuses?.[shipID] || { weapon:0, shield:0, armor:0, cargo:0, speed:0, fuel:0 }).forEach(entry =>
{
if(entry[0] == 'fuel' && entry[1] != 0) me.lifeformBonuses.ShipFuelConsumption = Math.abs(entry[1] / 100);
else me.lifeformBonuses.BaseStatsBooster[shipID][entry[0]] = entry[1] / 100;
});
});
if(data?.meAsDefender)
{
const planet = Object.values(ogl.db.myPlanets).find(e => e.coords == data.destination.coords && e.type == data.destination.type);
if(!planet) return;
ogl._account.defenseList.forEach(techID =>
{
me.defence[techID] = { count:planet[techID] };
});
}
// ################### enemy
const enemy = data?.meAsDefender ? player1 : player2;
if(data && !data.meAsAttacker) enemy.ships = data.ships;
['metal', 'crystal', 'deut', 'food'].forEach(e =>
{
player2.resources[e.replace('deut', 'deuterium')] = player2.ships?.[e]?.count || 0;
if(player1.ships?.[e]) delete player1.ships?.[e];
if(player2.ships?.[e]) delete player2.ships?.[e];
});
jsonData[0] = [player1];
jsonData[1] = [player2];
jsonData = btoa(JSON.stringify(jsonData));
let lang = ogl.account.lang == 'us' ? 'en' : ogl.account.lang == 'ar' ? 'es' : ogl.account.lang;
let toolID = ogl.db.options.sim && Util.simList[ogl.db.options.sim] ? ogl.db.options.sim : Object.keys(Util.simList)[Math.floor(Math.random() * Object.keys(Util.simList).length)];
const link = Util.simList[toolID];
if(apiKey) return link + lang + '?SR_KEY=' + apiKey + '#prefill=' + jsonData;
else return link + lang + '#prefill=' + jsonData;
}
static genConverterLink(ogl, apiKey)
{
let lang = ogl.account.lang == 'us' ? 'en' : ogl.account.lang == 'ar' ? 'es' : ogl.account.lang;
let toolID = ogl.db.options.converter && Util.converterList[ogl.db.options.converter] ? ogl.db.options.converter : Object.keys(Util.converterList)[Math.floor(Math.random() * Object.keys(Util.converterList).length)];
const link = Util.converterList[toolID];
if(toolID == 'ogotcha') return `${link}${lang}?CR_KEY=${apiKey}&utm_source=OGLight`;
else if(toolID == 'topraider') return `${link}?CR_KEY=${apiKey}&lang=${lang}`;
else if(toolID == 'ogame.tools') return `${link}?CR_KEY=${apiKey}`;
}
static genOgotchaLink(ogl, apiKey)
{
let lang = ogl.account.lang == 'us' ? 'en' : ogl.account.lang == 'ar' ? 'es' : ogl.account.lang;
return `https://ogotcha.universeview.be/${lang}?CR_KEY=${apiKey}&utm_source=OGLight`;
}
static genTopRaiderLink(ogl, apiKey)
{
let lang = ogl.account.lang == 'us' ? 'en' : ogl.account.lang == 'ar' ? 'es' : ogl.account.lang;
return `https://topraider.eu/index.php?CR_KEY=${apiKey}&lang=${lang}`;
}
static genMmorpgstatLink(ogl, playerID)
{
let lang = ['fr', 'de', 'en', 'es', 'pl', 'it', 'ru', 'ar', 'mx', 'tr', 'fi', 'tw', 'gr', 'br', 'nl',
'hr', 'sk', 'cz', 'ro', 'us', 'pt', 'dk', 'no', 'se', 'si', 'hu', 'jp', 'ba'].indexOf(ogl.server.lang);
return `https://www.mmorpg-stat.eu/0_fiche_joueur.php?pays=${lang}&ftr=${playerID}.dat&univers=_${ogl.server.id}`;
}
}
class PTRE
{
constructor(ogl)
{
this.ogl = ogl;
this.url = `https://ptre.chez.gg/scripts/`;
this.playerPositionsDelay = 1000*60*60;
this.manageSyncedListUrl = `https://ptre.chez.gg/?page=players_list`;
}
request(page, init)
{
const params = {};
const options = {};
if(document.querySelector('.ogl_ptreActionIcon i'))
{
if(this.ogl.ptreNotificationIconTimeout) clearTimeout(this.ogl.ptreNotificationIconTimeout);
document.querySelector('.ogl_ptreActionIcon i').className = 'material-icons ogl_warning';
document.querySelector('.ogl_ptreActionIcon i').classList.add('ogl_active');
}
Object.entries(init).forEach(obj =>
{
if(obj[0].indexOf('_') === 0) options[obj[0].replace('_', '')] = obj[1];
else params[obj[0]] = obj[1];
});
params.tool = 'oglight';
params.team_key = this.ogl.ptreKey;
params.country = this.ogl.server.lang;
params.univers = this.ogl.server.id;
params.version = this.ogl.version;
const strParams = !params ? '' : '?' + new URLSearchParams(params).toString();
return fetch(`${this.url}${page}${strParams}`, options)
.then(response => response.json())
.then(data =>
{
this.ogl.ptreNotificationIconTimeout = setTimeout(() => this.notify(data.message, data.code, data.message_verbose), 100);
return Promise.resolve(data);
});
}
notify(message, code, verbose)
{
if(!document.querySelector('.ogl_ptreActionIcon i')) return;
document.querySelector('.ogl_ptreActionIcon i').className = 'material-icons';
document.querySelector('.ogl_ptreActionIcon i').classList.remove('ogl_active');
if(code != 1)
{
this.log(code, verbose || message); // log errors
document.querySelector('.ogl_ptreActionIcon i').classList.add('ogl_danger');
}
else
{
document.querySelector('.ogl_ptreActionIcon i').classList.add('ogl_ok');
}
}
log(code, message)
{
const id = serverTime.getTime();
this.ogl.cache.ptreLogs = this.ogl.cache.ptreLogs || [];
this.ogl.cache.ptreLogs.push({code:code, message:message, id:id });
if(this.ogl.cache.ptreLogs.length > 10) this.ogl.cache.ptreLogs.shift();
}
displayLogs()
{
const container = Util.addDom('div', { class:'ogl_log' });
if(this.ogl.cache.ptreLogs?.length > 0)
{
this.ogl.cache.ptreLogs.forEach(log =>
{
const time = this.ogl._time.convertTimestampToDate(log.id);
Util.addDom('div', { child:`<div>${time.outerHTML}</div><div>${log.code}</div><div>${log.message}</div>`, prepend:container });
});
Util.addDom('div', { child:`<div>time</div><div>error code</div><div>message</div>`, prepend:container });
}
else
{
Util.addDom('div', { child:'empty', parent:container });
}
Util.addDom('div', { child:`<h2>PTRE errors</h2>`, prepend:container });
this.ogl._popup.open(container, true);
}
postPositions(postData)
{
this.request('api_galaxy_import_infos.php',
{
_method:'POST',
_body:JSON.stringify(postData)
});
}
postActivities(postData)
{
this.request('oglight_import_player_activity.php',
{
_method:'POST',
_body:JSON.stringify(postData)
})
.then(data =>
{
if(data.code == 1)
{
Object.keys(postData).forEach(id =>
{
const parent = document.querySelector(`.msg[data-msg-id="${id}"] .msg_title`);
if(parent && !document.querySelector(`.msg[data-msg-id="${id}"] .ogl_checked`)) Util.addDom('div', { class:'material-icons ogl_checked tooltipLeft ogl_ptre', child:'ptre', title:this.ogl._lang.find('ptreActivityImported'), parent:parent });
//if(this.ogl.page == 'messages') this.ogl.cache.counterSpies.push(id);
});
}
});
}
postPTRECompatibility(postData)
{
this.request('oglight_update_version.php',
{
_method:'POST',
_body:JSON.stringify(postData)
})
.then(data =>
{
if(data.code == 1)
{
this.ogl.id[1] = serverTime.getTime();
GM_setValue('ogl_id', this.ogl.id);
}
});
}
postSpyReport(apiKey)
{
this.request('oglight_import.php',
{
_method:'POST',
sr_id:apiKey
})
.then(data =>
{
this.ogl._notification.addToQueue(`PTRE: ${data.message_verbose}`, data.code == 1);
});
}
// export targets with the "ptre" flag
// import all ptre targets and give them the "ptre" flag
syncTargetList()
{
let json = [];
Object.values(this.ogl.db.udb).filter(u => u.pin == 'ptre').forEach(player => { json.push({ id:player.uid, pseudo:player.name }); });
this.request('api_sync_target_list.php',
{
_method:'POST',
_body:JSON.stringify(json)
})
.then(data =>
{
if(data.code == 1)
{
data.targets_array.forEach(playerData =>
{
const id = parseInt(playerData.player_id)
const player = this.ogl.db.udb[id] || this.ogl.createPlayer(id);
player.name = playerData.pseudo;
if(!player.pin) player.pin = 'ptre';
});
if(document.querySelector('.ogl_side.ogl_active') && this.ogl.db.lastPinTab == 'ptre')
{
this.ogl._topbar.openPinned();
}
}
this.ogl._notification.addToQueue(`PTRE: ${data.message}`, data.code == 1);
});
}
// player activities in frame
getPlayerInfo(player, frame)
{
const container = Util.addDom('div', { class:'ogl_ptreContent', child:'<div class="ogl_loading"></div>' });
this.ogl._popup.open(container);
frame = frame || 'week';
this.request('oglight_get_player_infos.php',
{
_method:'GET',
player_id:player.id,
pseudo:player.name,
input_frame:frame
})
.then(data =>
{
if(data.code == 1)
{
const arrData = JSON.parse(data.activity_array?.activity_array || '{}');
const checkData = JSON.parse(data.activity_array?.check_array || '{}');
container.innerHTML = `
<h3>${player.name}</h3>
<div class="ogl_ptreActivityBlock">
<div class="ogl_frameSelector"></div>
<div class="ogl_ptreActivities"><span></span><div></div></div>
</div>
<div class="ogl_ptreBestReport">
<div>${this.ogl._lang.find('reportFound')} (${new Date(data.top_sr_timestamp * 1000).toLocaleDateString('fr-FR')})</div>
<div>
<div class="ogl_fleetDetail"></div>
<b><i class="material-icons">rocket_launch</i>${Util.formatToUnits(data.top_sr_fleet_points)} pts</b>
</div>
<div>
<a class="ogl_button" target="_blank" href="${data.top_sr_link}">${this.ogl._lang.find('topReportDetails')}</a>
<a class="ogl_button" target="_blank" href="https://ptre.chez.gg/?country=${this.ogl.server.lang}&univers=${this.ogl.server.id}&player_id=${player.id}">${this.ogl._lang.find('playerProfile')}</a>
</div>
</div>
<!--<ul class="ogl_ptreLegend">
<li><u>Green circle</u>: no activity detected & fully checked</li>
<li><u>Green dot</u>: no activity detected</li>
<li><u>Red dot</u>: multiple activities detected</li>
<li><u>Transparent dot</u>: not enough planet checked</li>
</ul>-->
`;
Object.entries({ 'last24h':'Last 24h', '2days':'2 days', '3days':'3 days', 'week':'Week', '2weeks':'2 weeks', 'month':'Month' }).forEach(range =>
{
const button = Util.addDom('button', { class:'ogl_button', child:range[1], parent:container.querySelector('.ogl_frameSelector'), onclick:() =>
{
this.getPlayerInfo(player, range[0]);
}});
if(range[0] == frame) button.classList.add('ogl_active');
});
if(data.activity_array.succes == 1)
{
arrData.forEach((line, index) =>
{
if(!isNaN(line[1]))
{
let div = Util.addDom('div', { class:'tooltip', child:`<div>${line[0]}</div>` });
let span = div.appendChild(Util.addDom('span', { class:'ogl_ptreDotStats' }));
let dot = span.appendChild(Util.addDom('div', { 'data-acti':line[1], 'data-check':checkData[index][1] }));
let dotValue = line[1] / data.activity_array.max_acti_per_slot * 100 * 7;
dotValue = Math.ceil(dotValue / 30) * 30;
dot.style.color = `hsl(${Math.max(0, 100 - dotValue)}deg 75% 40%)`;
dot.style.opacity = checkData[index][1] + '%';
let title;
let checkValue = Math.max(0, 100 - dotValue);
if(checkValue === 100) title = '- No activity detected';
else if(checkValue >= 60) title = '- A few activities detected';
else if(checkValue >= 40) title = '- Some activities detected';
else title = '- A lot of activities detected';
if(checkData[index][1] == 100) title += '<br>- Perfectly checked';
else if(checkData[index][1] >= 75) title += '<br>- Nicely checked';
else if(checkData[index][1] >= 50) title += '<br>- Decently checked';
else if(checkData[index][1] > 0) title = 'Poorly checked';
else title = 'Not checked';
div.setAttribute('title', title);
if(checkData[index][1] === 100 && line[1] == 0) dot.classList.add('ogl_active');
container.querySelector('.ogl_ptreActivities > div').appendChild(div);
}
});
}
if(data.fleet_json)
{
this.ogl.shipsList.forEach(shipID =>
{
const shipData = data.fleet_json.find(e => e.ship_type == shipID);
if(shipData)
{
Util.addDom('div', { class:`ogl_icon ogl_${shipID}`, child:Util.formatToUnits(shipData.count), parent:container.querySelector('.ogl_fleetDetail') });
}
});
}
this.ogl._popup.open(container, true);
}
else
{
container.innerHTML = `${data.message}<hr><a target="_blank" href="https://ptre.chez.gg/?page=splash">More informations here</a>`;
}
});
}
// check for new positions
getPlayerPositions(playerData)
{
const updateList = () =>
{
if(document.querySelector('.ogl_pinDetail') && this.ogl.db.currentSide == playerData.id) // current pin
{
this.ogl._topbar.openPinnedDetail(playerData.id, true);
}
}
const player = this.ogl.db.udb[playerData.id] || this.ogl.createPlayer(playerData.player_id);
this.ogl._fetch.fetchPlayerAPI(playerData.id, playerData.name, () =>
{
if(this.ogl.ptreKey && serverTime.getTime() - (player.ptre || 0) > this.playerPositionsDelay)
{
this.request('api_galaxy_get_infos.php',
{
_method:'GET',
player_id:playerData.id,
})
.then(data =>
{
if(data.code == 1)
{
if(data.last_astro_level_seen > 0 && data.last_astro_level_seen_timestamp * 1000 > (player.liveUpdate || 0))
{
player.astro = data.last_astro_level_seen;
}
updateList();
player.ptre = serverTime.getTime();
data.galaxy_array.forEach(ptrePlanet =>
{
const oglPlanet = this.ogl.db.pdb[ptrePlanet.coords] || {};
if((oglPlanet.api || 0) < ptrePlanet.timestamp_ig)
{
oglPlanet.uid = ptrePlanet.player_id;
oglPlanet.pid = ptrePlanet.id;
oglPlanet.mid = ptrePlanet.moon?.id || -1;
oglPlanet.coo = ptrePlanet.coords;
oglPlanet.acti = ['60', '60', ptrePlanet.timestamp_ig];
// remove old planet owner
this.ogl.removeOldPlanetOwner(ptrePlanet.coords, ptrePlanet.player_id);
// add new planet owner
if(player.planets && player.planets.indexOf(ptrePlanet.coords) < 0)
{
player.planets.push(ptrePlanet.coords);
}
this.ogl.db.pdb[ptrePlanet.coords] = oglPlanet;
if(document.querySelector('.ogl_pinDetail') && this.ogl.db.currentSide == ptrePlanet.player_id)
{
this.ogl._topbar.openPinnedDetail(this.ogl.db.currentSide);
}
}
});
}
this.ogl._notification.addToQueue(`PTRE: ${data.message}`, data.code == 1);
});
}
else
{
updateList();
}
});
}
getRank(params, callback)
{
params = params || {};
this.request('api_get_ranks.php',
{
_method:'GET',
country:params.country || this.ogl.server.lang,
univers:params.univers || this.ogl.server.id,
timestamp:params.timestamp || -1,
})
.then(data =>
{
if(callback) callback(data);
});
}
}
class Datafinder
{
static getTech(id)
{
let tech =
{
// base building
1: { metal:60, crystal:15, deut:0, priceFactor:1.5 },
2: { metal:48, crystal:24, deut:0, priceFactor:1.6 },
3: { metal:225, crystal:75, deut:0, priceFactor:1.5 },
4: { metal:75, crystal:30, deut:0, priceFactor:1.5 },
12: { metal:900, crystal:360, deut:180, priceFactor:1.8 },
14: { metal:400, crystal:120, deut:200 },
15: { metal:1000000, crystal:500000, deut:100000 },
21: { metal:400, crystal:200, deut:100 },
22: { metal:1000, crystal:0, deut:0 },
23: { metal:1000, crystal:500, deut:0 },
24: { metal:1000, crystal:1000, deut:0 },
31: { metal:200, crystal:400, deut:200 },
33: { metal:0, crystal:50000, deut:100000, energy:1000, energyFactor:2 },
34: { metal:20000, crystal:40000, deut:0 },
36: { metal:200, crystal:0, deut:50, energy:50, priceFactor:5, energyFactor:2.5 },
41: { metal:20000, crystal:40000, deut:20000 },
42: { metal:20000, crystal:40000, deut:20000 },
43: { metal:2000000, crystal:4000000, deut:2000000 },
44: { metal:20000, crystal:20000, deut:1000 },
// base research
106: { metal:200, crystal:1000, deut:200 },
108: { metal:0, crystal:400, deut:600 },
109: { metal:800, crystal:200, deut:0 },
110: { metal:200, crystal:600, deut:0 },
111: { metal:1000, crystal:0, deut:0 },
113: { metal:0, crystal:800, deut:400 },
114: { metal:0, crystal:4000, deut:2000 },
115: { metal:400, crystal:0, deut:600 },
117: { metal:2000, crystal:4000, deut:600 },
118: { metal:10000, crystal:20000, deut:6000 },
120: { metal:200, crystal:100, deut:0 },
121: { metal:1000, crystal:300, deut:100 },
122: { metal:2000, crystal:4000, deut:1000 },
123: { metal:240000, crystal:400000, deut:160000 },
124: { metal:4000, crystal:8000, deut:4000, priceFactor:1.75 },
199: { metal:0, crystal:0, deut:0, energy:300000, priceFactor:3, energyFactor:3, durationFactor:1 },
// ship
202: { metal:2000, crystal:2000, deut:0 },
203: { metal:6000, crystal:6000, deut:0 },
204: { metal:3000, crystal:1000, deut:0 },
205: { metal:6000, crystal:4000, deut:0 },
206: { metal:20000, crystal:7000, deut:2000 },
207: { metal:45000, crystal:15000, deut:0 },
208: { metal:10000, crystal:20000, deut:10000 },
209: { metal:10000, crystal:6000, deut:2000 },
210: { crystal:1000, deut:0 },
211: { metal:50000, crystal:25000, deut:15000 },
212: { metal:0, crystal:2000, deut:500 },
213: { metal:60000, crystal:50000, deut:15000 },
214: { metal:5000000, crystal:4000000, deut:1000000 },
215: { metal:30000, crystal:40000, deut:15000 },
217: { metal:2000, crystal:2000, deut:1000 },
218: { metal:85000, crystal:55000, deut:20000 },
219: { metal:8000, crystal:15000, deut:8000 },
// def
401: { metal:2000, crystal:0, deut:0 },
402: { metal:1500, crystal:500, deut:0 },
403: { metal:6000, crystal:2000, deut:0 },
404: { metal:20000, crystal:15000, deut:2000 },
405: { metal:5000, crystal:3000, deut:0 },
406: { metal:50000, crystal:50000, deut:30000 },
407: { metal:10000, crystal:10000, deut:0 },
408: { metal:50000, crystal:50000, deut:0 },
// missile
502: { metal:8000, crystal:0, deut:2000 },
503: { metal:12000, crystal:2500, deut:10000 },
// lifeforms
"11101":{"type":"building","lifeform":"human","metal":7,"crystal":2,"deut":0,"priceFactor":1.2,"bonus1BaseValue":210,"bonus1IncreaseFactor":1.21,"bonus2BaseValue":16,"bonus2IncreaseFactor":1.2,"bonus3Value":9,"bonus3IncreaseFactor":1.15,"durationfactor":1.21,"durationbase":40},"11102":{"type":"building","lifeform":"human","metal":5,"crystal":2,"deut":0,"energy":8,"priceFactor":1.23,"energyIncreaseFactor":1.02,"bonus1BaseValue":10,"bonus1IncreaseFactor":1.15,"bonus2BaseValue":10,"bonus2IncreaseFactor":1.14,"durationfactor":1.25,"durationbase":40},"11103":{"type":"building","lifeform":"human","metal":20000,"crystal":25000,"deut":10000,"energy":10,"priceFactor":1.3,"energyIncreaseFactor":1.08,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"bonus1Max":0.25,"bonus2BaseValue":2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.25,"durationbase":16000},"11104":{"type":"building","lifeform":"human","metal":5000,"crystal":3200,"deut":1500,"energy":15,"priceFactor":1.7,"energyIncreaseFactor":1.25,"bonus1BaseValue":20000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.6,"durationbase":16000},"11105":{"type":"building","lifeform":"human","metal":50000,"crystal":40000,"deut":50000,"energy":30,"priceFactor":1.7,"energyIncreaseFactor":1.25,"bonus1BaseValue":100000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.7,"durationbase":64000},"11106":{"type":"building","lifeform":"human","metal":9000,"crystal":6000,"deut":3000,"energy":40,"priceFactor":1.5,"energyIncreaseFactor":1.1,"bonus1BaseValue":1.5,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"11107":{"type":"building","lifeform":"human","metal":25000,"crystal":13000,"deut":7000,"priceFactor":1.09,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"bonus2Max":0.8,"bonus3Value":0.8,"bonus3IncreaseFactor":1,"durationfactor":1.17,"durationbase":12000},"11108":{"type":"building","lifeform":"human","metal":50000,"crystal":25000,"deut":15000,"energy":80,"priceFactor":1.5,"energyIncreaseFactor":1.1,"bonus1BaseValue":1.5,"bonus1IncreaseFactor":1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.2,"durationbase":28000},"11109":{"type":"building","lifeform":"human","metal":75000,"crystal":20000,"deut":25000,"energy":50,"priceFactor":1.09,"energyIncreaseFactor":1.02,"bonus1BaseValue":1.5,"bonus1IncreaseFactor":1,"bonus2BaseValue":1.5,"bonus2IncreaseFactor":1,"durationfactor":1.2,"durationbase":40000},"11110":{"type":"building","lifeform":"human","metal":150000,"crystal":30000,"deut":15000,"energy":60,"priceFactor":1.12,"energyIncreaseFactor":1.03,"bonus1BaseValue":5,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":52000},"11111":{"type":"building","lifeform":"human","metal":80000,"crystal":35000,"deut":60000,"energy":90,"priceFactor":1.5,"energyIncreaseFactor":1.05,"bonus1BaseValue":0.5,"bonus1IncreaseFactor":1,"bonus1Max":1,"durationfactor":1.3,"durationbase":90000},"11112":{"type":"building","lifeform":"human","metal":250000,"crystal":125000,"deut":125000,"energy":100,"priceFactor":1.15,"energyIncreaseFactor":1.02,"bonus1BaseValue":3,"bonus1IncreaseFactor":1,"bonus1Max":0.9,"durationfactor":1.2,"durationbase":95000},"11201":{"type":"tech 1","lifeform":"human","metal":5000,"crystal":2500,"deut":500,"priceFactor":1.3,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":1000},"11202":{"type":"tech 2","lifeform":"human","metal":7000,"crystal":10000,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.06,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"11203":{"type":"tech 3","lifeform":"human","metal":15000,"crystal":10000,"deut":5000,"priceFactor":1.3,"bonus1BaseValue":0.5,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2500},"11204":{"type":"tech 4","lifeform":"human","metal":20000,"crystal":15000,"deut":7500,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":3500},"11205":{"type":"tech 5","lifeform":"human","metal":25000,"crystal":20000,"deut":10000,"priceFactor":1.3,"bonus1BaseValue":4,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":4500},"11206":{"type":"tech 6","lifeform":"human","metal":35000,"crystal":25000,"deut":15000,"priceFactor":1.5,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":5000},"11207":{"type":"tech 7","lifeform":"human","metal":70000,"crystal":40000,"deut":20000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":8000},"11208":{"type":"tech 8","lifeform":"human","metal":80000,"crystal":50000,"deut":20000,"priceFactor":1.5,"bonus1BaseValue":0.06,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":6000},"11209":{"type":"tech 9","lifeform":"human","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":6500},"11210":{"type":"tech 10","lifeform":"human","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":7000},"11211":{"type":"tech 11","lifeform":"human","metal":120000,"crystal":30000,"deut":25000,"priceFactor":1.5,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":7500},"11212":{"type":"tech 12","lifeform":"human","metal":100000,"crystal":40000,"deut":30000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":10000},"11213":{"type":"tech 13","lifeform":"human","metal":200000,"crystal":100000,"deut":100000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":8500},"11214":{"type":"tech 14","lifeform":"human","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9000},"11215":{"type":"tech 15","lifeform":"human","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9500},"11216":{"type":"tech 16","lifeform":"human","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":10000},"11217":{"type":"tech 17","lifeform":"human","metal":300000,"crystal":180000,"deut":120000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":11000},"11218":{"type":"tech 18","lifeform":"human","metal":500000,"crystal":300000,"deut":200000,"priceFactor":1.2,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":13000},"12101":{"type":"building","lifeform":"rocktal","metal":9,"crystal":3,"deut":0,"priceFactor":1.2,"bonus1BaseValue":150,"bonus1IncreaseFactor":1.216,"bonus2BaseValue":12,"bonus2IncreaseFactor":1.2,"bonus3Value":5,"bonus3IncreaseFactor":1.15,"durationfactor":1.21,"durationbase":40},"12102":{"type":"building","lifeform":"rocktal","metal":7,"crystal":2,"deut":0,"energy":10,"priceFactor":1.2,"energyIncreaseFactor":1.03,"bonus1BaseValue":8,"bonus1IncreaseFactor":1.15,"bonus2BaseValue":6,"bonus2IncreaseFactor":1.14,"durationfactor":1.21,"durationbase":40},"12103":{"type":"building","lifeform":"rocktal","metal":40000,"crystal":10000,"deut":15000,"energy":15,"priceFactor":1.3,"energyIncreaseFactor":1.1,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"bonus1Max":0.25,"bonus2BaseValue":2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.25,"durationbase":16000},"12104":{"type":"building","lifeform":"rocktal","metal":5000,"crystal":3800,"deut":1000,"energy":20,"priceFactor":1.7,"energyIncreaseFactor":1.35,"bonus1BaseValue":16000000,"bonus1IncreaseFactor":1.14,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.6,"durationbase":16000},"12105":{"type":"building","lifeform":"rocktal","metal":50000,"crystal":40000,"deut":50000,"energy":60,"priceFactor":1.65,"energyIncreaseFactor":1.3,"bonus1BaseValue":90000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.7,"durationbase":64000},"12106":{"type":"building","lifeform":"rocktal","metal":10000,"crystal":8000,"deut":1000,"energy":40,"priceFactor":1.4,"energyIncreaseFactor":1.1,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"12107":{"type":"building","lifeform":"rocktal","metal":20000,"crystal":15000,"deut":10000,"priceFactor":1.2,"bonus1BaseValue":1.5,"bonus1IncreaseFactor":1,"bonus2BaseValue":0.5,"bonus2IncreaseFactor":1,"bonus2Max":0.4,"durationfactor":1.25,"durationbase":16000},"12108":{"type":"building","lifeform":"rocktal","metal":50000,"crystal":35000,"deut":15000,"energy":80,"priceFactor":1.5,"energyIncreaseFactor":1.3,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"bonus2Max":0.5,"durationfactor":1.4,"durationbase":40000},"12109":{"type":"building","lifeform":"rocktal","metal":85000,"crystal":44000,"deut":25000,"energy":90,"priceFactor":1.4,"energyIncreaseFactor":1.1,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":40000},"12110":{"type":"building","lifeform":"rocktal","metal":120000,"crystal":50000,"deut":20000,"energy":90,"priceFactor":1.4,"energyIncreaseFactor":1.1,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":52000},"12111":{"type":"building","lifeform":"rocktal","metal":250000,"crystal":150000,"deut":100000,"energy":120,"priceFactor":1.8,"energyIncreaseFactor":1.3,"bonus1BaseValue":0.5,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"durationfactor":1.3,"durationbase":90000},"12112":{"type":"building","lifeform":"rocktal","metal":250000,"crystal":125000,"deut":125000,"energy":100,"priceFactor":1.5,"energyIncreaseFactor":1.1,"bonus1BaseValue":0.6,"bonus1IncreaseFactor":1,"bonus1Max":0.3,"durationfactor":1.3,"durationbase":95000},"12201":{"type":"tech 1","lifeform":"rocktal","metal":10000,"crystal":6000,"deut":1000,"priceFactor":1.5,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":1000},"12202":{"type":"tech 2","lifeform":"rocktal","metal":7500,"crystal":12500,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"12203":{"type":"tech 3","lifeform":"rocktal","metal":15000,"crystal":10000,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2500},"12204":{"type":"tech 4","lifeform":"rocktal","metal":20000,"crystal":15000,"deut":7500,"priceFactor":1.3,"bonus1BaseValue":0.4,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":3500},"12205":{"type":"tech 5","lifeform":"rocktal","metal":25000,"crystal":20000,"deut":10000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":4500},"12206":{"type":"tech 6","lifeform":"rocktal","metal":50000,"crystal":50000,"deut":20000,"priceFactor":1.5,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":5000},"12207":{"type":"tech 7","lifeform":"rocktal","metal":70000,"crystal":40000,"deut":20000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":5500},"12208":{"type":"tech 8","lifeform":"rocktal","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":6000},"12209":{"type":"tech 9","lifeform":"rocktal","metal":75000,"crystal":55000,"deut":25000,"priceFactor":1.5,"bonus1BaseValue":0.15,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.3,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":6500},"12210":{"type":"tech 10","lifeform":"rocktal","metal":85000,"crystal":40000,"deut":35000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":7000},"12211":{"type":"tech 11","lifeform":"rocktal","metal":120000,"crystal":30000,"deut":25000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":7500},"12212":{"type":"tech 12","lifeform":"rocktal","metal":100000,"crystal":40000,"deut":30000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":8000},"12213":{"type":"tech 13","lifeform":"rocktal","metal":200000,"crystal":100000,"deut":100000,"priceFactor":1.2,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.1,"bonus2IncreaseFactor":1,"durationfactor":1.3,"durationbase":8500},"12214":{"type":"tech 14","lifeform":"rocktal","metal":220000,"crystal":110000,"deut":110000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":9000},"12215":{"type":"tech 15","lifeform":"rocktal","metal":240000,"crystal":120000,"deut":120000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":9500},"12216":{"type":"tech 16","lifeform":"rocktal","metal":250000,"crystal":250000,"deut":250000,"priceFactor":1.4,"bonus1BaseValue":0.5,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":10000},"12217":{"type":"tech 17","lifeform":"rocktal","metal":500000,"crystal":300000,"deut":200000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":13000},"12218":{"type":"tech 18","lifeform":"rocktal","metal":300000,"crystal":180000,"deut":120000,"priceFactor":1.7,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":11000},"13101":{"type":"building","lifeform":"mecha","metal":6,"crystal":2,"deut":0,"priceFactor":1.21,"bonus1BaseValue":500,"bonus1IncreaseFactor":1.205,"bonus2BaseValue":24,"bonus2IncreaseFactor":1.2,"bonus3Value":22,"bonus3IncreaseFactor":1.15,"durationfactor":1.22,"durationbase":40},"13102":{"type":"building","lifeform":"mecha","metal":5,"crystal":2,"deut":0,"energy":8,"priceFactor":1.18,"energyIncreaseFactor":1.02,"bonus1BaseValue":18,"bonus1IncreaseFactor":1.15,"bonus2BaseValue":23,"bonus2IncreaseFactor":1.12,"durationfactor":1.2,"durationbase":48},"13103":{"type":"building","lifeform":"mecha","metal":30000,"crystal":20000,"deut":10000,"energy":13,"priceFactor":1.3,"energyIncreaseFactor":1.08,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"bonus1Max":0.25,"bonus2BaseValue":2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.25,"durationbase":16000},"13104":{"type":"building","lifeform":"mecha","metal":5000,"crystal":3800,"deut":1000,"energy":10,"priceFactor":1.8,"energyIncreaseFactor":1.2,"bonus1BaseValue":40000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.6,"durationbase":16000},"13105":{"type":"building","lifeform":"mecha","metal":50000,"crystal":40000,"deut":50000,"energy":40,"priceFactor":1.8,"energyIncreaseFactor":1.2,"bonus1BaseValue":130000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.7,"durationbase":64000},"13106":{"type":"building","lifeform":"mecha","metal":7500,"crystal":7000,"deut":1000,"priceFactor":1.3,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":2000},"13107":{"type":"building","lifeform":"mecha","metal":35000,"crystal":15000,"deut":10000,"energy":40,"priceFactor":1.5,"energyIncreaseFactor":1.05,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"bonus1Max":1,"bonus2BaseValue":0.3,"bonus2IncreaseFactor":1,"durationfactor":1.4,"durationbase":16000},"13108":{"type":"building","lifeform":"mecha","metal":50000,"crystal":20000,"deut":30000,"energy":40,"priceFactor":1.07,"energyIncreaseFactor":1.01,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"bonus2BaseValue":2,"bonus2IncreaseFactor":1,"durationfactor":1.17,"durationbase":12000},"13109":{"type":"building","lifeform":"mecha","metal":100000,"crystal":10000,"deut":3000,"energy":80,"priceFactor":1.14,"energyIncreaseFactor":1.04,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"bonus2BaseValue":6,"bonus2IncreaseFactor":1,"durationfactor":1.3,"durationbase":40000},"13110":{"type":"building","lifeform":"mecha","metal":100000,"crystal":40000,"deut":20000,"energy":60,"priceFactor":1.5,"energyIncreaseFactor":1.1,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":52000},"13111":{"type":"building","lifeform":"mecha","metal":55000,"crystal":50000,"deut":30000,"energy":70,"priceFactor":1.5,"energyIncreaseFactor":1.05,"bonus1BaseValue":0.4,"bonus1IncreaseFactor":1,"bonus1Max":1,"durationfactor":1.3,"durationbase":50000},"13112":{"type":"building","lifeform":"mecha","metal":250000,"crystal":125000,"deut":125000,"energy":100,"priceFactor":1.4,"energyIncreaseFactor":1.05,"bonus1BaseValue":1.3,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"durationfactor":1.4,"durationbase":95000},"13201":{"type":"tech 1","lifeform":"mecha","metal":10000,"crystal":6000,"deut":1000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":1000},"13202":{"type":"tech 2","lifeform":"mecha","metal":7500,"crystal":12500,"deut":5000,"priceFactor":1.3,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"13203":{"type":"tech 3","lifeform":"mecha","metal":15000,"crystal":10000,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.03,"bonus1IncreaseFactor":1,"bonus1Max":0.3,"durationfactor":1.4,"durationbase":2500},"13204":{"type":"tech 4","lifeform":"mecha","metal":20000,"crystal":15000,"deut":7500,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":3500},"13205":{"type":"tech 5","lifeform":"mecha","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":4500},"13206":{"type":"tech 6","lifeform":"mecha","metal":50000,"crystal":50000,"deut":20000,"priceFactor":1.5,"bonus1BaseValue":0.06,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":5000},"13207":{"type":"tech 7","lifeform":"mecha","metal":70000,"crystal":40000,"deut":20000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":5500},"13208":{"type":"tech 8","lifeform":"mecha","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":6000},"13209":{"type":"tech 9","lifeform":"mecha","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":6500},"13210":{"type":"tech 10","lifeform":"mecha","metal":85000,"crystal":40000,"deut":35000,"priceFactor":1.2,"bonus1BaseValue":0.15,"bonus1IncreaseFactor":1,"bonus1Max":0.9,"durationfactor":1.3,"durationbase":7000},"13211":{"type":"tech 11","lifeform":"mecha","metal":120000,"crystal":30000,"deut":25000,"priceFactor":1.3,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":7500},"13212":{"type":"tech 12","lifeform":"mecha","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":8000},"13213":{"type":"tech 13","lifeform":"mecha","metal":200000,"crystal":100000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.06,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":8500},"13214":{"type":"tech 14","lifeform":"mecha","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9000},"13215":{"type":"tech 15","lifeform":"mecha","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9500},"13216":{"type":"tech 16","lifeform":"mecha","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":10000},"13217":{"type":"tech 17","lifeform":"mecha","metal":500000,"crystal":300000,"deut":200000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":13000},"13218":{"type":"tech 18","lifeform":"mecha","metal":300000,"crystal":180000,"deut":120000,"priceFactor":1.7,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":11000},"14101":{"type":"building","lifeform":"kaelesh","metal":4,"crystal":3,"deut":0,"priceFactor":1.21,"bonus1BaseValue":250,"bonus1IncreaseFactor":1.21,"bonus2BaseValue":16,"bonus2IncreaseFactor":1.2,"bonus3Value":11,"bonus3IncreaseFactor":1.15,"durationfactor":1.22,"durationbase":40},"14102":{"type":"building","lifeform":"kaelesh","metal":6,"crystal":3,"deut":0,"energy":9,"priceFactor":1.2,"energyIncreaseFactor":1.02,"bonus1BaseValue":12,"bonus1IncreaseFactor":1.15,"bonus2BaseValue":12,"bonus2IncreaseFactor":1.14,"durationfactor":1.22,"durationbase":40},"14103":{"type":"building","lifeform":"kaelesh","metal":20000,"crystal":15000,"deut":15000,"energy":10,"priceFactor":1.3,"energyIncreaseFactor":1.08,"bonus1BaseValue":0.25,"bonus1IncreaseFactor":1,"bonus1Max":0.25,"bonus2BaseValue":2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.25,"durationbase":16000},"14104":{"type":"building","lifeform":"kaelesh","metal":7500,"crystal":5000,"deut":800,"energy":15,"priceFactor":1.8,"energyIncreaseFactor":1.3,"bonus1BaseValue":30000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.7,"durationbase":16000},"14105":{"type":"building","lifeform":"kaelesh","metal":60000,"crystal":30000,"deut":50000,"energy":30,"priceFactor":1.8,"energyIncreaseFactor":1.3,"bonus1BaseValue":100000000,"bonus1IncreaseFactor":1.1,"bonus2BaseValue":1,"bonus2IncreaseFactor":1,"durationfactor":1.8,"durationbase":64000},"14106":{"type":"building","lifeform":"kaelesh","metal":8500,"crystal":5000,"deut":3000,"priceFactor":1.25,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"durationfactor":1.35,"durationbase":2000},"14107":{"type":"building","lifeform":"kaelesh","metal":15000,"crystal":15000,"deut":5000,"priceFactor":1.2,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":12000},"14108":{"type":"building","lifeform":"kaelesh","metal":75000,"crystal":25000,"deut":30000,"energy":30,"priceFactor":1.05,"energyIncreaseFactor":1.03,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"bonus2BaseValue":6,"bonus2IncreaseFactor":1,"durationfactor":1.18,"durationbase":16000},"14109":{"type":"building","lifeform":"kaelesh","metal":87500,"crystal":25000,"deut":30000,"energy":40,"priceFactor":1.2,"energyIncreaseFactor":1.02,"bonus1BaseValue":200,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":40000},"14110":{"type":"building","lifeform":"kaelesh","metal":150000,"crystal":30000,"deut":30000,"energy":140,"priceFactor":1.4,"energyIncreaseFactor":1.05,"bonus1BaseValue":2,"bonus1IncreaseFactor":1,"bonus1Max":0.3,"durationfactor":1.8,"durationbase":52000},"14111":{"type":"building","lifeform":"kaelesh","metal":75000,"crystal":50000,"deut":55000,"energy":90,"priceFactor":1.2,"energyIncreaseFactor":1.04,"bonus1BaseValue":1.5,"bonus1IncreaseFactor":1,"bonus1Max":0.7,"durationfactor":1.3,"durationbase":90000},"14112":{"type":"building","lifeform":"kaelesh","metal":500000,"crystal":250000,"deut":250000,"energy":100,"priceFactor":1.4,"energyIncreaseFactor":1.05,"bonus1BaseValue":0.5,"bonus1IncreaseFactor":1,"bonus1Max":0.3,"durationfactor":1.3,"durationbase":95000},"14201":{"type":"tech 1","lifeform":"kaelesh","metal":10000,"crystal":6000,"deut":1000,"priceFactor":1.5,"bonus1BaseValue":0.03,"bonus1IncreaseFactor":1,"bonus1Max":0.3,"durationfactor":1.4,"durationbase":1000},"14202":{"type":"tech 2","lifeform":"kaelesh","metal":7500,"crystal":12500,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.08,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":2000},"14203":{"type":"tech 3","lifeform":"kaelesh","metal":15000,"crystal":10000,"deut":5000,"priceFactor":1.5,"bonus1BaseValue":0.05,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"durationfactor":1.4,"durationbase":2500},"14204":{"type":"tech 4","lifeform":"kaelesh","metal":20000,"crystal":15000,"deut":7500,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":3500},"14205":{"type":"tech 5","lifeform":"kaelesh","metal":25000,"crystal":20000,"deut":10000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":4500},"14206":{"type":"tech 6","lifeform":"kaelesh","metal":50000,"crystal":50000,"deut":20000,"priceFactor":1.3,"bonus1BaseValue":0.4,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":5000},"14207":{"type":"tech 7","lifeform":"kaelesh","metal":70000,"crystal":40000,"deut":20000,"priceFactor":1.5,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":5500},"14208":{"type":"tech 8","lifeform":"kaelesh","metal":80000,"crystal":50000,"deut":20000,"priceFactor":1.2,"bonus1BaseValue":0.6,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":6000},"14209":{"type":"tech 9","lifeform":"kaelesh","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":6500},"14210":{"type":"tech 10","lifeform":"kaelesh","metal":85000,"crystal":40000,"deut":35000,"priceFactor":1.2,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"durationfactor":1.2,"durationbase":7000},"14211":{"type":"tech 11","lifeform":"kaelesh","metal":120000,"crystal":30000,"deut":25000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":7500},"14212":{"type":"tech 12","lifeform":"kaelesh","metal":100000,"crystal":40000,"deut":30000,"priceFactor":1.5,"bonus1BaseValue":0.06,"bonus1IncreaseFactor":1,"durationfactor":1.3,"durationbase":8000},"14213":{"type":"tech 13","lifeform":"kaelesh","metal":200000,"crystal":100000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"bonus1Max":0.99,"durationfactor":1.3,"durationbase":8500},"14214":{"type":"tech 14","lifeform":"kaelesh","metal":160000,"crystal":120000,"deut":50000,"priceFactor":1.5,"bonus1BaseValue":1,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9000},"14215":{"type":"tech 15","lifeform":"kaelesh","metal":240000,"crystal":120000,"deut":120000,"priceFactor":1.5,"bonus1BaseValue":0.1,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":9500},"14216":{"type":"tech 16","lifeform":"kaelesh","metal":320000,"crystal":240000,"deut":100000,"priceFactor":1.5,"bonus1BaseValue":0.3,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":10000},"14217":{"type":"tech 17","lifeform":"kaelesh","metal":500000,"crystal":300000,"deut":200000,"priceFactor":1.5,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"bonus1Max":0.5,"bonus2BaseValue":0.2,"bonus2IncreaseFactor":1,"bonus2Max":0.99,"durationfactor":1.3,"durationbase":13000},"14218":{"type":"tech 18","lifeform":"kaelesh","metal":300000,"crystal":180000,"deut":120000,"priceFactor":1.7,"bonus1BaseValue":0.2,"bonus1IncreaseFactor":1,"durationfactor":1.4,"durationbase":11000}
}
return tech[parseInt(id)];
}
}
GM_addStyle(`@font-face{font-family:Material Icons;src:url(data:font/woff2;base64,d09GMgABAAAAACZ4AAsAAAAAUqgAACYnAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJceBmAAk1QK3mTNSAE2AiQDhFgLgi4ABCAFhFsHjFQbGkh1B8j1OIDkOHcW0qzFqTOiilSe/f9fkxtDFGagNfv/ELWyJKaSqdoW7OiqA0eFBrvgOJp3nCICkXrpRD09l27ln/xa9sarDIG4UGJ21ocP22Gm8SpfKDa7fuTPO7TQxYGhraeTfkiSNHkeu70vQWJxiygPkOIoPGhlQbsgCW6I3Kyh7FIWVhYVwwwaWAskQaM0TTPSbCm7FlIBU+Fdks65acWadFK9L5DSTK41+NJN0a/qVf9aF7818CHd+l4Qy8KKsWawZvpFLTYhk4EQAnyB3d+deKVSnVd3VXFFb4e6qqrSqrvMkgfueMCwSN29SDMtqe6Bo0ROrVS2h56bZhnTf7ax0mLAMqAbSan1e+8LAJ7n8Q+9P0ShpKBzCitwBQxrpy57t+lNzWlqG/uwmy6M7BQKPXY2tY19LGHyBSCFMMLOdTkeoAmGXK7VPgzfzHxNW3vPvvhw+eupk7l33a4ciHySGFMAC4B2lJF1HWK7EK0N1quk3zkGC7nNrxIBlu19xU8GpAHU1gU2BM2AddpfR4vsvjoZP637uZTKKyAJagXFuqTDVsWDogDSaEckhPHw8HOxfKFfiF4QXrE3+YyD7fbb2jikiyFJ19pN/r3Osr1j316wTCrgzk2RtvB/kuFJsvB2J1+Lko5kBywvyj4Cxxuk6ibVVVunkmQvaB2Q7COyHcIyXWaLKlAB9SmaKv97Ju8IDQP8CaqY42r7k520V5pOoCstH2eZDWEKl8DezC74d2Pk2ygBKvanWnLXwb2L7/9vb9m2Y8xPkvSTJOMMY67/wG4Nj0xzoxmaYaKM5Xv/77cRAD0qQS0QztcvbQfknfXRbQACMR6OBuB7cu50htcD6Xk7xJPSQPqZ8WUgH1SC/9hqhUeEr4sUohrR98Rq8UUMYLV4UKKT/Cv9SdYoXyfvlr9DyIEEKuAAq8AecBEMgR8DMdS+AoxJoirj/SxFVMAMtVxYQ7jkIY6XmdOZnFwikeShglBFhl8qUIiok588HJew88N2vrGjxEQxNy8ZQT2OKmjUxkmj//5Qv0qLrol/9IuiAjauIPqYUyOgSPRJNCpLlKKGTENvG1OFUSgXkhjUzx9VYFCmev6iaJa8TEpNokhv1dJ/xVWmgEjl84sibc0NK5mePB+RJ+d8robGiTLbwxH0lUot4UE0JJjACsu5ZURFMQUt4KKzTYGecDKbKFbsGSQeH+T0Oa6wcWm0ISDpKWsKVXFdYzje2JwklibM87idR61OD/GUSKElQhKRhY+4mIYTRh9w2IBEiTeatsqPElGsj6khxUWxdX4SQtcCkc7emrXGmwZYLptJmZHBavfwaZlo6IpkWvU+l+VKM5UpBGq836xNp+TwkVG9jNa5EkZ4uM2DWPWUJyPqoXj9rBTF/JD9MsPH4cDjCacc3TZdcMesfFwo0KiS4UENcJmhw3MC89FWSjfFBmyKh/AZlwmSdIaTTh+0pjlunal4q0Xn3CNq4o/IRARz0Ksi2qyZ36FRtWTTpjqi9gohK5ET1WcSBA1zn4kWrW/gSKI2cridFW88atkxl5xjh+ZSQqUR+sFEqdPuIs6SWqkzgAaZCoiztoxUeZ6TFBL0FEcokOJuXOIpNwHjMzzzv8A89Sqy/n6St/5wR7jG2IyrQDNmsg0Gg1cizbBd6KJlVT0+XxFlHajWjyrMduxB8m6yXXD6Mflw6TJzQu4czDXIrpw0IoceaohJ7si4dKoYdvZJqelRYNC+O2j2vc9rVSCdIqMqggerejbJViOA6gaZc9M7QkhZJR6RClSSSTaZhfoT0tGy/kdF3pUQNmbROp0QpExhVKUFEd/Vqv6VFXWx27h9twTO+ujHP40K6QfobZKAUiXRnIIobkYHvsqDVEULEjKii28khMzu9bfzIt1RG4cznVt3llJFNw4ecKiKMoHZA67CsmZDq2Wk5aDLoCXdIq7Cd8/4lBh1zAPxNz7/yaZY5GOSZJlgqWNWpFk0s9O2nlnrZru4JLG7jCAJ8BAJ3LmCbT5CY4FhHPAdFWSy6Ld4o+OOMtXzE2sKjG1QN/aAV4Lf59on3IYSxzkQRWhDF0b39IRLloBUb3aAa46VATeXpG71aDFJYhxzl2C+pyp1zQJo6LrMHkwYUG3TjYw/2Qff/mF3evyAgwvgttJmgKF3O41gHVXtvyEnLdzxnKkyegsEK7Fa3JpMo7nAsz/Ryzw3IsevmasbkCDvpkhaF7mJeyET0UvZVwHj8Xe4VupCw7rGKSak1znT6ECu+KDGTc/nCthdDhm+gm3XoF5RDmaiLrL6Ft/jIqiDT8iodUM9rzK2WxAhfSDuoj8RTsKslGBdBtYZjOXiPjHY2pqgolrpSdVg1dXrmgt4fGQ0+mqrFtkR4+TCEhpKtovM4hSnMbsz5Y5/HIvGjLiZsM6eLf3a4R/glRP8d2DO+3f/k2sXSjhL8fAC+64sXMFPplfk6kBr/Lv3ZaAtwIvSs/FQBiX/5j3FX8CNKux8ox1FBDTpb9rBXN16DTtPjvj//5uKi+FWAApSFmKz4POL5y8zqxFiORA3HdOzMU1CiQqvi/4wQpaOHmaO3PXj5cqTr1i1VoMWXHLVTXfxcvgFVKgUNmLekrPO2bDpOE6pwk/Ro0efAVOmzbnilia9hjRoc0aZZuN23RDSb9KsC655ysmrTqNtJ1102T2PzVhx4I4af5zLKSVuO+2RJ0bVpWMmPLj+OW7Z80y7h6p06HRMgUJF7E6ot69LuaD7Wqyr1W3VmkXX7ViGogIP7Z//u1cd+AT/9x8QHooGjSdTejamJRTJfM0sIqejh5kjHFrUAZVTDP6Cuc/0GRbQR1hEH2AFfYKz9ACcp1vgAj0EF+k2uEQv4DI9hiv0EtrpLXTQO+ikJ9BFX6GbnkMPPQK99Br66B7opztggF7BIP2Aq/QUrtEbuE73wQ26C27Ke+v1AfnMbkB+kwrIL/iAy3cEQCUEhxoIHo0QApogRDRDSBgOIWMchIJZECqWQWjYDKHjAoSByxAmOiEs9ELYFSMcqBgBoWIEgooRGNACQdAKQTEdgmElhItNEB62Qvg4DRHgDESI3RAR9kDEOAqRoIBIMRIiwwqIHGchClRBlFgIUWExRI2lEA3WQ7Rog+iwEaLHJYgBXRBjw9VNgEUQM5ZDLJgMsVY+YgOcgtgxGuLADIgTayAuHIC40QHxYBrE2+C6D7AO4scGSADnIEFcgYRwAxJGOSSCakgUEyExTIHEsQ+SwHFIEuchKVyEpNEHyeAaJNtw9RxstkNwGFJAD6SI8ZASyiBlVEAqOAGpYgSkhm5IHSchDVyFNHEd0sIqSBtNkA6aIV2shvSwFtLHAGSAEsgQeyGjRq6PATchE8yBTDEImWEsZI65kAXmQZY4AllhCGSNoZANhkG2KIXsGgt9D5gEOeAQ5Ij5kBPGQM4YBbls+iGYCblhF+SOCZAHFkCe2AF5YSfkjS2QD9ohX+yH/P7YBvgJijnlxylorAea54cVktaXlzy+Bxry9buNMmCmMZmhwxnq5oA+w/gsj3Mx3ckPtsgzbZ1jycIX71noO5kMs5uETFUHFVkcO2/czIN4MKVp0Rnnn3tY+KoYdYABbgaDaiIpPjjpx7zMgtDSTMxnC2/wMbrABx04/2sPjkfVxLF0mXO3V5mIuQE6nB4MA1I6JNrjJRty6PXQ7pJj+PC8TMEnO/yPJzekqdUhBh6qzCIWqYomEzFXFNBEesZRxtUb0XalTNN82lSmqaQ0eK/sxzKwmJe4jGY0P3OAvtyzCPijKmZ2jlbW63sjpow6WKiikBN0DvoJNq4QCRsQME1DyOdom1jO54dqf+IHg7IOCG4QwmZm/JTAUzYuBRkYPdzgl+CQL1As/CLMnxrZbFVvCuV7/m+7lRntPBxP/3w8hl1+/KfXXFOjFmkPGyXpAXcYk3ix/zZzkhsGcWUPGQa5ELIrrSkEzxRNK/Thvw1gdWQuyrW77cZR3QcvlV0f5hmHEVYBXTYS/I4ol3rxqYrV9Xio8vGf/YaepO5+elQ9/vw+vP340D/48KYIrdTFEPi9dFGsDlTXExESNn5RghVnBuFAAQiQwRNyDFQz7MW5QMitA6PbscJzO54WZd6Zyn2yhioGajQAt4MH1kbbcbcukLhIqB5iFUx7Zb/LchiAJ4ltjCSLfinzPuborEjyzCAJtH47sPWw+hw++g8MMdYkl/mx7q7JOjjidI52fw87ImG9O2K94vhZkWLAdZYz837E1jNfeH2sDsf+64ymWlX3mQOvWqKYyieHtOJg+xkViG+Yp0IA5zrAV2eCDM5RzaouNJAkJy+0DDMyXfPcaa1BL3wkMo5/PHL+7DH7CwNW0F27et0B461rcF3gKu7wLOJkRBh8S/EQu40XY911WXGM4XIbWen/1kV9QyRdi8N5WctkdBMGf5r7C6PqU/3Bf5RwrS71yZ9vhdbr+wjeevGifvXqHqK3X760NWWCHDiuFsU2EBuMCO9RBZjuJKCaAExfUnjoKOXA4yIBKkHvxV3754AayQaY/bvVKVVqbgZmn/3T86oB8ced3v3pXk6bkcdu3f6Nv+92VWMUSM1nAvMTcCFFskCRgQC960Fxpp/1zpgOgnAZhzPGwQ0M+b4IEgTMKwURtsZBkV1U+ELYDOo1ziL/PIZ1tIshIXOcMUDpvsJU3lAfEyNlkYm4i3ytkXrzjRNZYxrF+vOWQ0NlbYbq9hwDJYlSDx6bHQ7ZNI91iR3mHF+8hY9GhDueVrMw8eNTZql6VD/wD0sUEGCgXjd4Yuri3Tlg1FWRogdzC6sRV6blahXx4MMJqQ/VMez97gpzOCaHBCYo2Jls6MQUA0IGwluMeR0BtdVIR57wRQbbh7fhnsMPzbXM0hIz1C4hu6gRAQG1ta4o/p5iFaUuDlnDIFjNTneniDwPerpfxY9PdCYAhJpgTkzLr5wautbhlJRhrZOz3DJNkUj7YzoSIl4AmgsVT1tmRBieNQkaesMEQ4f6bqfjyBrKWkM5cKyYXl90UuTgrSwSp1vWkanbaMkFVK/LgXf1W0pytpbFL7746kg4Xaf+oAefA12SHih47HWwi0wbGHb4Dspc+4EwVqqegcHEKq1OihweAgQ+vzQuADBIXpiSaCQs68ULizUWKCjK+lO111A9VwSzum7I3bUwacBGRSf5GV5nWxgJECNlrCvIjsC4GbIEG/+9/skldcGUGrnUBjRt2naaW6QoHGudphSN1sVxiqgpAc1yx6tWkwLN8ZZaaaRhAiMKw+TDI0vcKotEJy31v0vEw4J1pLjmjiLDIcjT0CFGQLUyC2aR3mowaOU1JD6VrLyTKss9ReBzQO21pHlFTk7reB8N2V0UNA6Mfxq5pZp9xqtgpEmMNB1X1k7tgtba7J+JwoKbk6LkHARjVFU8HWAJOsrncYomfyhrAmZ9wC6kPsCpP5ClOpDa7rTRY+jZbRtL2FSfk3hS3L+yUnt0fbLF/eXqU0zZto8oHW8aMDElLdLfqgaWrbrNcUfdmerz8jI8zCDnUbSmCzJWo9XbKhsPABg4p1/sibyaYjX7Pwdo2Mj4nqLYHE/TRvPj/1CNhETetX7hx59GY4DN8K6SMYygRWY6Wmx03hn/g/AXqUrmHtzMcXAz7zEm0ansT2qPpvLC4w/r7XBfbSIKOvBUWek4ohmedq0/WbLz+SfEVYjOsnJGJArTVni5bLNMKcpicrlML6cwzRnLKpWfGU4YKznnBksiUZzn2/7/qFs08bQPLbqJHkUwAyNXBMn3HDVfyZOxe+ydejuc6vs1dEWalyrLTULFV1M9PI/dajHCQOvrOtVQ2cgv7aM971aFV62FfTJwRPEO9LpbmBzlgM94r0OBh/FyZGGlbqTa7nHYa5Flm7TSuuPppvTR3on7k/M3E7XQyN3x8S6H1ZBqK9kdHBsIWoXneQsDG6zBcNzcEPVXpeItRh7W0a661VTi8GkA402u3im3btgBKhF/i1bgD7hEqom6kzO5sMSBsU6SNDRdkZ6ck2Vz3vTt8lp+1/Y3lbBJhO2G2pNMZ+5rMHVArTmGsYMWh868mzN5q0trVsWht8g7K/GgATuWO9xaq3CDaR+ebobnV7cSWF1L+ww+NjdDtr2+HV1cBAoyXIyzWZ7l55a3S+X969HwKbPaS9K8tWUOTXvlfEMS15m7Pon1I3+OahfYTjEKSuhNa6ZDfBXB0lCsn0LA7VKuz2M9BZB2kWba8JHo3RT0B7dJZSw/9F1jN4D2qwuiwIanU9nZt040oPjCVvsTkG9apI+cP4146sLRNP2Wv26gOn7uBBjg5NljSfKVY/WphfcdMYIOg63a2pojDPvHxMYsgW2Ei0CabCpGo+s101tUoXbryeBDSSQknL9m3lGQcGBtngJmn1SYIC/4/HXtjghg85UQO4/dvuOiqXA7GfWNaHMQKerkAa+Bw5ya3c9067PiwaZSWa8xkrnoF+OlOpPiTPTrhQZ9UKRPvsLGIdshsp5MoTA7rqXymrtCIcMVnJa0uaA9I6rGYV1WlELWpNgUzbog40TpyVA3kIAFe/tL0VrCAIfUExFnDpM7bOmCaAiA4RZRL6MXfg9Css3u3iB3xXAt6094/b0F7r/nMM/5mshiisT2W3r64QuzYE+A0Zjm/D43kB1Fe9n6ExMVzy3grPIHYzNX+jgdi84UGbN2JJfK6n6Hyx+EQQdynrchOXLaTns/5FG3S98DBOIFhi3TIx2LnjY9vahj3vQWWee5r88Y6v4bMcx9znDov9OGM1/rI4pd6y2UIL9601MK6nv1GKAs63eBcKy5mea+c/S99wYEcYal6axcvi9LgzezN+CNloeBGLM/a1iZMWQVuDu37CXL/1Qu9NDe/JEeoWGKllZWN+zIidbWqwYJqBNb63RVi5r+tV0x9RF2uHkRiEPd36xMDWP9W03c+I0C4p2LF595Xl0+eWTWHssr0QAHFX43/wApOtmeODDGOCLLi2q72aBgjyR6IqU7x5gI6w3iRo0nVoZ0mESJ4uyVElwHy6p/GPXRI8dyYyO0b9NIdRnU4S2+mA6VxTyVLgd0oDAW+KSNZdf/XGqYMig2r8ry//c4RRZLatawrJWwpqwEeDwW5gdD4cGolO+6qmI5aA3ZHzNiY8gYcOpC1btgcIhZsoTu37eXBknmu0o9MgLuxEfUwdGmfVRGkKnLkUh/qTWTDWpv7LEEtLuopmYhhcSm09E6/vl8FV3bujYK/hdW1i7wajLmjAYSWZ3lvQtqlVSIDlE45+Mk1qXoIoJuAZcNJdEbFSpOJBui7lMpqVgY66cbMFlSlZRhDXR/TCiWpj6iDclEKu4GPNNV8cMfVix3gDGf385lLtBXDmjM5YXXc1EArV5eu7x7Ue3WalgNXTCKTAjEOc2UOeRWXx/AxSzebKmon+zQlHsUJYX5H22a/LumQuF2FbZslWAGKtw3T+worrIZplzAA8QfWLwzzd6iTZkzP/FVZM/am6Qh54a/W9ftv5FjIG+u7VG6yJ6XDTSna1tPx+gBSRsyYTyGlB+/LH75YyUC/iZkUvEqhIdwpUMZIfqo31uZz0Ty/QMdd4oviUs3WbTBnf/PaygBIUo/npmaLvnG+e4Hg2MaGa79dd7S+ZWDgvWO0/sFwdIedt6SJf2OfTee/98jo1AA/EYiTTxDIreSVboR+Qx0cja0B9n4gxsc2EjTakqtfkhtL65cfh7wwKQQUr37iFtdL+7RuyoUMp2HpDK2IaUXHlaEcbDv97RXnL4V3981sDt34MRuZ65BeWUvwOUxeAGPUHIY7EUzkgjFOJwXPtLhWcPom/DNUYPfD/h5zz1rvSC/YFVb5hE11mefG3hOTRmAH9o3cor4VXT83MBw2Pjei3PRLIzEZqG5L75nLDibCb3xWKUduLkM+TAcx3xo2c0Breqde6HMS2zc6IfQ74cCxavCl5DskBiHyxBloy70MLlmpW2l+SLBUMJvRC5o4hJp7UQkglxauDOwCtphO7Ij1nXHjvx2l6LT9FF6AsSN+qJU7Hs5+sGZVObBxxlq5qA+53uxVNGgw0bf8tANlhJpIgVTF0j8iIymiCwHGKY3vRTneZfTBeJx/4A6VISWLIVFTshecLsDvajJiDBM4kgBA/fCRImyyN12wRN7oF/cVQSXLkFFoc+ICRCz4TzOLl1fv02WlG2rf5At7lWEnG3dOQ08Ftk9CC0c10I37LFVnHKI3GjMdSgBjA2tYPQQlDCtq3ed1zoTcCnIitU63eoKEook3XgezCfysQji3PGg11+2r8xfvdmXtCQJT6NPnmTf0Is7FmMUTyr7Wo6IKYJ0QCLLSumJtvW/l4DuuDVTGtJUsv5nIGHEeEyUR703OEo5RRiPi3Kp0f73qCoRvtubS01eHfkI4vYb09REWS9gREaxedZU+7hq3NfnWy7HA95t2+jKKNfnDVBBz/D5VDW2wuOm8oT4QO1VUSnwn3Khk3K7qVw8l/ohVYfV5Vx5WB6VopzJej4FbpzXW3g/lMt7+3NDKybpsv70QKlhyhdQBdtT9KTHo/N6KSdoSHCMfqMEG3AEAGfjTJq0Oa2xOyEy5dNyOZ1vQnACxAdjbw9BNzs6yrrhUIBEvYgEUSLLCZSfjr0eGDnE7YYINqMAiGuyR+O50MwmBBHE1bA5iO9iGMPIiAHEnxtxqUPgsHsYvLgwUQF/vBiGzr53DLE/yuLGoAkmoBvCbiKjeyb27G9PPnCDoNluEIfIztrVjFVcvWSJ6roLSabeqLXUvnF5TZ/ZeO7hSiz/4Tmjue9sbblSIY9yjY7UNeG1hco5qVZHKtcoK4qmPFNwZ1c7f01fs+JS++TJN+pJktwa/IF/GKVQ0gZTMGk/FT/iMJ4IxXZXIfoqawluOuwO5Eg6ZEyig4ZxJ06QElBCZSGmjfqCrdPrJSRNEolYajLHs1RymKR1NOnO28TFWBcbd+IhRegCjI0Kq9CFizxTDlPUjVRhOqxihyHHw0QvY0T4duKHu2rehMBDpIkEyk/EpVyAcyLOpRAEjAyaRmkXnIZp5+k7BmzdxZrov71mBSnHL9pWHvz9gt9ubdggJy8Pfvvt4GVSvqFh62+5opQvIFWF6JBKGvABHt2zQ3YogiJPs4i9x8GeoUTaU+b3tydEJvi8Ds2HhSETukeImWJrw9iv/8h8pPzbH9WIiIzag5NQgvbsAEQ1LhUDptsa1l9IPnOg+6nsgfry6WnH86UeXVHrD2nxtSU/P1jjvXGhibkurGvJE855DjY2LlZTrntvt/ue3G35VV8BPgkaiDQx7ovBzb4DN14qhUE2yDPBiSh089oJ0wSwuWBuWH5b5uSp7Lb87aOCnJHIqIPItDpNM+PG4jkvFsuOLO6ttG/p/DKzUHTt+VLCsmKxCveDWB6vMraBVXPAtrKSOTf0r77dahALfrf3n1d+Ny/z1uGRfyhefxgof1kprfScoYGhoPRV+6Tw0Ttkjl5VVmerd3jtd0pmLT/wU5VqunRx6BZcEFZQWsEMgZYCscJ93KKIJNLG+xbYlqT8nJZ1+W2tZOuzxo1dnQu7QDpmMqEfJQb9C0yHnU4d4cqIFy/OGzIPzbv4IlEGPs8aUikaviND8qTynGJ8hZa2wLsHyGIdPVy8p5GXnFPE7BPsidkx8NU3DLb8wFAmlNxV9kteu0ONH7n2Moa+on608TZ9e+OPqK8Q9vK1I+MCkYz+7wu3D/W0t1DYL29FIy/8lz69ke6nf7q300eq5aXfGETStvAXv3Mr+z706DW+Bs9xwsJalv0AScz7glo9Fsbfu43lgksvSfrJAXKQvHrsKvnZjfU/xY0+I16IzT5Eygap1MGNr7k3tL7iH97/s00zsB88o1732sFfrl3rPVD65d3cqxv9UvUv3Sr2ydplHpm3rEGZ/kBxSbD6s38uztVtRnkfHzaNREOAcyXP+3UMh4gM3Dy1KuTNGSKN4wFePg1EfZhVuGjsIxLIUtQdzeESFYCFTwNAqteVCB4CREX6Ha+/VbJOK2yMAkD3fucJ0ynjdwAdAPxP7aS9J9kWtPLlKlzl3brgwtm1zbqV81v1rTMlex1fF8MDurvD1XnQ5ttvbuhwfmd/VcuZrcdIi86qW6MpLTbrpr95ly1cK62st4LjLv2XtV/q22na9R1M0+35X5m+yu+AIG7bageXF8Q+LEXBIKqJeTQ+ZUwDPMXrjp0Cfujx0J5+B2Sve8yHDgJdjAKaGTzi/hJdueN45RqcrW+8fr1VzYaJV0sCREZJvzeZp3j1nSvoS3cEB/oXedsv1gvznf0mfpAeadaJWV3zqGGIN/p5zVTBlCZTAO6wAyXOKmyh5/X8lCFED/VHcp2vAt7oYHHr5pL12OnHL2/tW88QvX7zobhbP3lpjcGTC7SqFjYqDntOrVxG6tsHTatZJc4TPM5FspL9CXnwLQXE4ba2K1fJUqopnCglB/YeQ1ebON8DxOE7C1utLZzR5Bbrav67fycbmE6m0IsxIPq7UJz/3QL7YFNVVXT7ci2m1C7fHt39mwlbtJQiwawHZ7Ev937ZfSOaBE5uNVV/NE+OtGaqk5g6EnZ57uZrfmUZ5kh7k6srfe0kN2z5VY0JIghRPHBiR9+RVU3btzc/VVDrkfy69OwRtY7riMNbLKhTHztrf1UC+LTrVRnugPa39ZeQzSmQS9ROGCTiE1AhQI1wZyGb5ZuvARgvsMyYF2io7ZCUrFRqpFbqdeqWKvCDrVH0osuhzicL6+uveKRtR4/+JRr1Xbx0+/z50rktt88n2qPRuX8+B9BtZBiWUWeVOExcyvp/TWh0MFQQ7gsX8P2jK6xy67SVoMcuX1aFC0KDoyErUYogt64Y7ecLwtTlK/Zh3ul02P2nBh5U6sn5NK/0kUnHP4I591MWPWTbMpFtDANmRr1+Q7vHXYxYFhb/tVhbwG9Ejlmi48Fj+VqSyChEvchHjUNq848Fj4tmOVBPnxWSirHlFQ5WYVmX2qJt9ktjChK6DMDvgh3ScojqMLIUBuLGFN3XR2/aUJxKFffng7UvZmdb5mS/nEc4ph/XLP1DtMCrjmosXuhCy9wLz6obYe09wP9vIGGPv5EYDmXCkXApvANMIlnpiDEQ50TO6svxFIVz01WMvVDHODakS1fI2MFw9n9ADLt6DHtGjGvDGOIcnio6wCByVNSe4V/yX3A4+31LsxISWOMgHhTMeBZeQACAikxRdy1DgjLIeF8mE1RntKEhboof/BkAG6aD4aEM2Ghj9nD5DIB9Q1Khse1YZVDgpMXEGxfEOlwMkhiYgpAoa9PBaTdNeSGtGGQR49kwBsC0b6Oylm4s1TA1DZHNGGqjFlPf2uQTMTaWYhAQPLhMEHzMIiy4tx4rKYLUBjqOXTTNQCpNkxzSOE+DFCi7BQtZaceg+kiIPhYMrz1vF1Sl8JpkVhF1sR2D84KiskVQSrsdCqvumQrSbO+dDoukXasqEZtodbjcSAuGWEiVqdiZwhWImgFEn4go8AoBgAAMTz62dOQsxPo8PDcNxYnqj4c03lG0iTtW/RuvfQFFG85EFAfjz5a/I/rcsCkEa3tXIND/Il48Hfl/MF2TP0SxKTpg0alzC2Sh9ITFYFTGGqAcrwcq+I1DjTYr12sVesKOK/OCU8ncgU3A+8GOY18EB2B/gVOJv8Gl3P/gc6zQvgEvlEtdN8ihmcrhxyhsf2FohfRz4ANuqf+gloUPN5fXtcze/h4MLX2c6dDNBzsNt+79oVeZDt8JO0qRQ1X5hOiXo3v9eHXVgy5cRpnu/EoOzVQOP0Zh+2tHh/b49kk7HTOe/y9Ae4JiitPfXF53PuRx/fc8Q7bVmQ7dHIXZabh17w/IVpkC/jsy21HCohwqvtEnRL8cCez68QrW67vylyNL0z9wfSQywq3/oEmlG6b1V1exHq/j84MQjKD//Apsf5sCoUgskcrkCqVK63dBq9MbjCazxWqzO5wut8cLgv2BYCgciern7kFhcAQShcZgcXgCkUSmUGl0hn+j8f/GZLE5XB5fIBSJJVKZXKFUqTVand5gNJktVpvd4XS5PV7ePr5+SCxqHmLKpbY+5trnvq8+OhdjlMYeOirEEUsqGbwjVTlXR+LxcXpXkjOfp6RAxe+96r3oXnhYGGq16WK31FwUjPO6Q/I8YdkVicdFJ8VX3ZntGXZdG4Kiivqya7mkp3Hk0BIsjkitIBg4LXM0Hu9GS5xUOBT0fg+sonkYfRWzxoIHceg1CEUoQcPt9dft316Xr2EThV3J/EEinOTUGSr5uIz0lPM2tg4X16TrOJ+9ju9K5NSp2Cd6kE45nauETrMd7ytw3Ac2IPq73EcJpxwRfIROYk6+Tpkm4bRNIjqbfguQ+QIp+z2ysuiaY2CKe4+mEmyecu41PtciintxFLGmCF+gsu4puui8Kf05iWbHkz530DARNypBEUXTts8FIUqd9ycg3qGOuVsqeId+ASzS3L7gczgrVXrQOHoWts0Ahudoy6FIh+1InGykIzYnnK+z8mKUCfdGaToUMgteFlscgXr3iLmT9a95ksvyTr1H1fFW3zxOS9K6glpmWaUHX5em8Ka8PmaPI3hTiIdGAxYlmy8PgfaoSKQSBrLA7p1Z+H7F28Zca+ZhMVEuFg/ctpMkhBHku0k4u2iT8c0kNY9aS95Kvtxj+BntGHivgy3jbJUq9B6L5z7HwQt2X4Zyk7NDn0tByvtZnmrBtlI8ftJwuyPaz4QDpXQvZcXccbeO4vLhNUFpVbOSYz6sEMN3wsyI/jyqKoPCLFD0fMo+L6or1nVWmnLa/9+g85SvzBaKJGtFr7BxpaggX6nEI/we/IBQqHEclyrNsVGzFdcWMzhiZSCN4wY9Nr0KSAIpdNc982BLO7ZSllaBdNeqqFuwKIqFOeneXOWI0LdXvbDWpazg1PR6gtrGWNlZNNnCZo57V3Aast3Q6spV6jgvGifZN+6lpLASwatWEzm2p4zzxSKvujtly10u2ef1mZRXFRapT0EjicGmtwrEWpnK7NBI5UadxZC2t0NsPvNf7XSbLgA=)format("woff2");font-style:normal;font-weight:400}`);