NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Galaxy Flight Duration // @namespace https://openuserjs.org/users/LukaNebo // @version 1.5.2 // @description Script to display flight duration inside Galaxy. // @author LukaNebo // @license MIT // @copyright 2024, LukaNebo (https://openuserjs.org/users/LukaNebo) // @match https://*.ogame.gameforge.com/game/* // @updateURL https://openuserjs.org/meta/LukaNebo/galaxy_flight_duration.meta.js // @downloadURL https://openuserjs.org/install/LukaNebo/galaxy_flight_duration.user.js // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // ==/UserScript== // *** FETCH SERVER DATA *** // Local storage for saved server data const SERVER_DATA_LOCAL_STORAGE_KEY = "GFD_serverData"; let serverData; if (!localStorage.getItem(SERVER_DATA_LOCAL_STORAGE_KEY)) { // Assign server ID from OGame meta tag let serverId = document.querySelector("meta[name=ogame-universe]").content; // Fetch data from .../api.serverData.xml GM_xmlhttpRequest({ method: "GET", url: "https://" + serverId + "/api/serverData.xml", onload: function(response) { // Parse the XML response let parser = new DOMParser(); let xmlDoc = parser.parseFromString(response.responseText, "application/xml"); // Extract the values let galaxyNum = parseInt(xmlDoc.querySelector("galaxies").textContent, 10); let fleetIgnoreEmptySystems = parseInt(xmlDoc.querySelector("fleetIgnoreEmptySystems").textContent, 10) == 1 ? 1 : 0; let fleetIgnoreInactiveSystems = parseInt(xmlDoc.querySelector("fleetIgnoreInactiveSystems").textContent, 10) == 1 ? 1 : 0; // Log variables that are fetched from .../api.serverData.xml console.log("*** Galaxy Flight Duration ***\n\nNumber of galaxies: ", galaxyNum, "\nIgnore Empty Sistems: ", fleetIgnoreEmptySystems, "\nIgnore Inactive Systems: ", fleetIgnoreInactiveSystems); serverData = { galaxyNum: galaxyNum, fleetIgnoreEmptySystems: fleetIgnoreEmptySystems, fleetIgnoreInactiveSystems: fleetIgnoreInactiveSystems, }; // Save "serverData" to localStorage localStorage.setItem(SERVER_DATA_LOCAL_STORAGE_KEY, JSON.stringify(serverData)); }, onerror: function(error) { console.error("*** Galaxy Flight Duration ***\n\nError fetching data from .../api/serverData.xml site:", error); } }); } else { serverData = JSON.parse(localStorage.getItem(SERVER_DATA_LOCAL_STORAGE_KEY)); } let ignoreSystemsCheck = (serverData.fleetIgnoreEmptySystems == 0 || serverData.fleetIgnoreInactiveSystems == 0) ? false : true; // *** CONFIG *** const COLORS = { gray: "#848484", red: "#D43635", yellow: "#FFD700", green: "#99CC00", blue: "#6F9FC8", fleetSpeedType: [/* peaceful */"#36B588", /* war */"#D43635", /* holding */"#D57936"], briefingSelector: [/* one way */"#315c81", /* two way */"#595959", /* arrival */"#99CC00", /* return */"#595959"], speedModifier: [/* 100% */"#1E8f00", /* 90% */"#72B900", /* 80% */"#C2E100", /* 70% */"#FFFA00", /* 60% */"#FFDF00", /* 50% */"#FFC400", /* 40% */"#FFA900", /* 30% */"#FF7A00", /* 20% */"#FF4900", /* 10% */"#FF1700"], speedModifierGeneral: [/* 100% */"#068300", /* 95% */"#399c00", /* 90% */"#60b000", /* 85% */"#86c300", /* 80% */"#acd600", /* 75% */"#d2e900", /* 70% */"#fafd00", /* 65% */"#fff400", /* 60% */"#ffe600", /* 55% */"#ffd900", /* 50% */"#ffcb00", /* 45% */"#ffbe00", /* 40% */"#ffb100", /* 35% */"#ffa100", /* 30% */"#ff8800", /* 25% */"#ff6f00", /* 20% */"#ff5600", /* 15% */"#ff3e00", /* 10% */"#ff2500", /* 5% */"#ff0c00"], }; const LOCALES = { en: { ships: { fighterLight: ["Light Fighter", "LF"], fighterHeavy: ["Heavy Fighter", "HF"], cruiser: ["Cruiser", "Cruiser"], battleship: ["Battleship", "BS"], interceptor: ["Battlecruiser", "BC"], bomber: ["Bomber", "Bomber"], destroyer: ["Destroyer", "Destro."], deathstar: ["Deathstar", "RIP"], reaper: ["Reaper", "Reaper"], explorer: ["Pathfinder", "PF"], transporterSmall: ["Small Cargo", "SC"], transporterLarge: ["Large Cargo", "LC"], colonyShip: ["Colony Ship", "Colony S."], recycler: ["Recycler", "Recycler"], espionageProbe: ["Espionage Probe", "Probe"], }, shipTypes: { first: "first", second: "second", third: "third", }, title: { distance: { distance: "Distance", coordsDifference: "Difference in position", galaxy: ["galaxy", "galaxies"], system: ["system", "systems"], positionSetTo16: "Position co-ordinates are always set to 16!", ignoreSystems: "Ignore systems (empty/inactive)" }, fleetSpeed: { selectedSpeed: "Selected speed", types: { peaceful: "Peaceful", war: "War", holding: "Holding" }, fleetSpeed: "fleet speed.", missionTypesStr: "Missions affected by this fleet speed", missionTypes: { peaceful: "Expedition, Colonisation, Transport, Deployment", war: "Recycle Debris Field, Espionage, Attack, ACS Attack, Moon Destruction", holding: "ACS Defend" }, clickStr: "Click to cycle through peaceful/war/holding fleet speed" }, briefingSelector: { oneWay: "One way flight duration selected", twoWay: "Two way flight duration selected", arrival: "Arrival time selected", return: "Return time selected", clickStr: "Click to toggle between One or Two way flight duration and Arrival or Return time" }, speedModifier: "Speed modifier", ship: { selected: "Selected", ship: " ship:", speed: "Speed", clickStr: "Click to change to a different ship", warningStr: "WARNING: Ship's speed is not updated!\nGo to Fleet page to update speed values." }, infoBtn: { savedSpeedValues: "Saved speed values", uniSettings: "Universe Settings", fleetSpeed: "Peaceful/War/Holding Fleet Speed", donut: "Donut Galaxy/System", galaxyNum: "Number of galaxies", ignoreSystems: "Ignore Empty/Inactive Systems" }, }, }, de: { ships: { fighterLight: ["Leichter Jäger", "L. Jäger"], fighterHeavy: ["Schwerer Jäger", "S. Jäger"], cruiser: ["Kreuzer", "Kreuzer"], battleship: ["Schlachtschiff", "SS"], interceptor: ["Schlachtkreuzer", "SK"], bomber: ["Bomber", "Bomber"], destroyer: ["Zerstörer", "Zerstörer"], deathstar: ["Todesstern", "RIP"], reaper: ["Reaper", "Reaper"], explorer: ["Pathfinder", "PF"], transporterSmall: ["Kleiner Transporter", "KT"], transporterLarge: ["Großer Transporter", "GT"], colonyShip: ["Kolonieschiff", "Kolonies."], recycler: ["Recycler", "Recycler"], espionageProbe: ["Spionagesonde", "Sonde"], }, shipTypes: { first: "erste", second: "zweite", third: "dritte", }, title: { distance: { distance: "Entfernung", coordsDifference: "Unterschied in der Position", galaxy: ["Galaxie", "Galaxien"], system: ["System", "Systeme"], positionSetTo16: "Positionskoordinaten sind immer auf 16 gesetzt!", ignoreSystems: "Ignoriere Systeme (leer/inaktiv)" }, fleetSpeed: { selectedSpeed: "Ausgewählte Geschwindigkeit", types: { peaceful: "friedlich", war: "krieg", holding: "halten" }, fleetSpeed: "Flottengeschwindigkeit.", missionTypesStr: "Missionen betroffen durch diese Fluggeschwindigkeit", missionTypes: { peaceful: "Expedition, Kolonisieren, Transport, Stationieren", war: "Trümmerfeld abbauen, Spionage, Angreifen, Verbandsangriff, Zerstören", holding: "Halten" }, clickStr: "Drücken Sie hier, um die Geschwindigkeit der friedlichen/kriegerischen/halten Flotte zu wechseln" }, briefingSelector: { oneWay: "OEinweg-Flug ausgewählt", twoWay: "Zweiweg-Flugdauer ausgewählt", arrival: "Ankunftszeit ausgewählt", return: "Rückflugzeit ausgewählt", clickStr: "Drücken Sie hier, um zwischen der Dauer eines Hin- oder Rückflugs und der Ankunfts- oder Rückflugzeit zu wechseln" }, speedModifier: "Geschwindigkeitsmodifikator", ship: { selected: "Ausgewählt", ship: " Schiff:", speed: "Geschwindigkeit", clickStr: "Drücken Sie, um zu einem anderen Schiff zu wechseln", warningStr: "WARNUNG: Die Geschwindigkeit des Schiffs wird nicht aktualisiert!\nGehen Sie zur Flotten-Seite, um die Geschwindigkeitswerte zu aktualisieren." }, infoBtn: { savedSpeedValues: "Gespeicherte Geschwindigkeitswerte", uniSettings: "Universumseinstellungen", fleetSpeed: "Friedliche/Kriegerische/Halten Flottengeschwindigkeit", donut: "Donut-Galaxie/System", galaxyNum: "Anzahl der Galaxien", ignoreSystems: "Leere/Inaktive Systeme ignorieren" }, }, }, fr: { ships: { fighterLight: ["Chasseur léger", "C. léger"], fighterHeavy: ["Chasseur lourd", "C. lourd"], cruiser: ["Croiseur", "Croiseur"], battleship: ["Vaisseau de bataille", "VB"], interceptor: ["Traqueur", "Traqueur"], bomber: ["Bombardier", "Bombar."], destroyer: ["Destructeur", "Destru."], deathstar: ["Étoile de la mort", "RIP"], reaper: ["Faucheur", "Faucheur"], explorer: ["Éclaireur", "Éclaireur"], transporterSmall: ["Petit transporteur", "PT"], transporterLarge: ["Grand transporteur", "GT"], colonyShip: ["Vaisseau de colonisation", "V. de colo."], recycler: ["Recycleur", "Recycleur"], espionageProbe: ["Sonde d`espionnage", "Sonde"], }, shipTypes: { first: "premier", second: "deuxième", third: "troisième", }, title: { distance: { distance: "Distance", coordsDifference: "Différence de position", galaxy: ["galaxie", "galaxies"], system: ["système", "systèmes"], positionSetTo16: "Les coordonnées de position sont toujours réglées sur 16 !", ignoreSystems: "Ignorer les systèmes (vides/inactifs)" }, fleetSpeed: { selectedSpeed: "Vitesse sélectionnée", types: { peaceful: "pacifique", war: "guerre", holding: "attente" }, fleetSpeed: "vitesse de la flotte.", missionTypesStr: "Missions affectées par cette vitesse de la flotte", missionTypes: { peaceful: "Expédition, Coloniser, Transporter, Stationner", war: "Recycler le champ de débris, Espionner, Attaquer, Attaque groupée, Détruire", holding: "Stationner (ACS)" }, clickStr: "Cliquez pour basculer entre les vitesses pacifiques/guerrières/d'attente de la flotte" }, briefingSelector: { oneWay: "Durée de vol à sens unique sélectionnée", twoWay: "Durée de vol aller-retour sélectionnée", arrival: "Heure d'arrivée sélectionnée", return: "Heure de retour sélectionnée", clickStr: "Cliquez pour alterner entre la durée du vol aller simple ou aller-retour et l'heure d'arrivée ou de retour" }, speedModifier: "Modificateur de vitesse", ship: { selected: "Sélectionné", ship: " vaisseau:", speed: "vitesse", clickStr: "Cliquez pour changer de vaisseau", warningStr: "ATTENTION : La vitesse du vaisseau n'est pas mise à jour !\nAllez à la page de la flotte pour mettre à jour les valeurs de vitesse." }, infoBtn: { savedSpeedValues: "Valeurs de vitesse enregistrées", uniSettings: "Paramètres de l'univers", fleetSpeed: "Vitesse de la flotte pacifique/guerrière/d'attente", donut: "Galaxie/système Donut", galaxyNum: "Nombre de galaxies", ignoreSystems: "Ignorer les systèmes vides/inactifs" }, }, }, it: { ships: { fighterLight: ["Caccia Leggero", "Caccia L"], fighterHeavy: ["Caccia Pesante", "Caccia P"], cruiser: ["Incrociatore", "Incroc."], battleship: ["Nave da battaglia", "Nave Batt"], interceptor: ["Incrociatore da Battaglia", "Incr Batt"], bomber: ["Bombardiere", "Bomb"], destroyer: ["Corazzata", "Corazzata"], deathstar: ["Morte Nera", "RIP"], reaper: ["Reaper", "Reaper"], explorer: ["Pathfinder", "PF"], transporterSmall: ["Cargo leggero", "Cargo L"], transporterLarge: ["Cargo Pesante", "Cargo P"], colonyShip: ["Colonizzatrice", "Colonizz."], recycler: ["Riciclatrici", "Ricicl"], espionageProbe: ["Sonda spia", "Sonda"], }, shipTypes: { first: "primo", second: "secondo", third: "terzo" }, title: { distance: { distance: "Distanza", coordsDifference: "Differenza di posizione", galaxy: ["galassia", "galassie"], system: ["sistema", "sistemi"], positionSetTo16: "Le coordinate di posizione sono sempre impostate su 16!", ignoreSystems: "Ignora sistemi (vuoti/inattivi)" }, fleetSpeed: { selectedSpeed: "Velocità di flotta selezionata", types: { peaceful: "Pacifica", war: "Guerra", holding: "Stazionamento" }, fleetSpeed: "", missionTypesStr: "Missioni influenzate da questa velocità di flotta", missionTypes: { peaceful: "Spedizione, Colonizzazione, Trasporto, Schieramento", war: "Ricicla campo detriti, Spionaggio, Attacco, Attacco federale, Distruzione Luna", holding: "Stazionamento" }, clickStr: "Clicca per passare alla velocità di flotta Pacifica/Guerra/Stazionamento" }, briefingSelector: { oneWay: "Durata selezionata del volo in andata", twoWay: "Durata selezionata del volo andata e ritorno", arrival: "Orario di arrivo selezionato", return: "Orario di ritorno selezionato", clickStr: "Clicca per passare tra la durata del volo in andata o andata e ritorno e orario di arrivo o di ritorno" }, speedModifier: "Modificatore di velocità", ship: { selected: "Nave selezionata", ship: ":", speed: "Velocità", clickStr: "Clicca per cambiare con un'altra nave", warningStr: "ATTENZIONE: La velocità della nave non è aggiornata!\nVai alla pagina Flotta per aggiornare i valori di velocità." }, infoBtn: { savedSpeedValues: "Valori di velocità salvati", uniSettings: "Impostazioni universo", fleetSpeed: "Velocità della flotta Pacifica/Guerra/Stazionamento", donut: "Galassia/Sistema circolare", galaxyNum: "Numero di galassie", ignoreSystems: "Ignora Sistemi Vuoti/Inattivi" }, }, }, br: { ships: { fighterLight: ["Caça Ligeiro", "CL"], fighterHeavy: ["Caça Pesado", "CP"], cruiser: ["Cruzador", "Cruzador"], battleship: ["Nave de Batalha", "NB"], interceptor: ["Interceptador", "Inter"], bomber: ["Bombardeiro", "BB"], destroyer: ["Destruidor", "DD"], deathstar: ["Estrela da Morte", "EdM"], reaper: ["Ceifeira", "Ceifeira"], explorer: ["Explorador", "Explor"], transporterSmall: ["Cargueiro Pequeno", "Cargo P"], transporterLarge: ["Cargueiro Grande", "Cargo G"], colonyShip: ["Nave Colonizadora", "Nave Colo"], recycler: ["Reciclador", "Reciclador"], espionageProbe: ["Sonda de Espionagem", "Sonda"], }, shipTypes: { first: "primeira", second: "segunda", third: "terceira", }, title: { distance: { distance: "Distância", coordsDifference: "Diferença de posição", galaxy: ["galáxia", "galáxias"], system: ["sistema", "sistemas"], positionSetTo16: "As coordenadas da posição são sempre definidas como 16!", ignoreSystems: "Ignorar sistemas (vazios/inativos)" }, fleetSpeed: { selectedSpeed: "Velocidade selecionada", types: { peaceful: "pacífica", war: "agressiva", holding: "manter" }, fleetSpeed: "", missionTypesStr: "Missões afetadas por essa velocidade de frota", missionTypes: { peaceful: "Expedição, Colonizar, Transportar, Transferir", war: "Reciclar campo de destroços, Espionar, Atacar, Ataque de aliança, Destruir", holding: "Guardar Posições" }, clickStr: "Clique para alternar entre a velocidade da frota pacífica/agressiva/manter" }, briefingSelector: { oneWay: "Duração do voo só de ida selecionada", twoWay: "Duração do voo ida e volta selecionada", arrival: "Hora de chegada selecionada", return: "Tempo de retorno selecionado", clickStr: "Clique para alternar entre a duração do voo de ida ou de volta e o tempo de chegada ou de retorno" }, speedModifier: "Modificador de velocidade", ship: { selected: "Selecionado", ship: " nave:", speed: "Velocidade", clickStr: "Clique para mudar para uma nave diferente", warningStr: "AVISO: A velocidade da nave não é atualizada! Vá para a página Fleet (Frota) para atualizar os valores de velocidade." }, infoBtn: { savedSpeedValues: "Valores de velocidade salvos", uniSettings: "Configurações do universo", fleetSpeed: "Velocidade da frota pacífica/agressiva/manter", donut: "Galáxia/sistema circular", galaxyNum: "Número de galáxias", ignoreSystems: "Ignorar sistemas vazios/inativos" }, }, }, si: { ships: { fighterLight: ["Lahek lovec", "L. lovec"], fighterHeavy: ["Težki lovec", "T. lovec"], cruiser: ["Križarka", "Križarka"], battleship: ["Bojna ladja", "BL"], interceptor: ["Bojna križarka", "BK"], bomber: ["Bombnik", "Bombnik"], destroyer: ["Uničevalec", "Unič."], deathstar: ["Zvezda smrti", "RIP"], reaper: ["Kombajn", "Kombajn"], explorer: ["Iskalec sledi", "IS"], transporterSmall: ["Majhna tovorna ladja", "MTL"], transporterLarge: ["Velika tovorna ladja", "VTL"], colonyShip: ["Kolonizacijska ladja", "Koloni. l."], recycler: ["Recikler", "Recikler"], espionageProbe: ["Vohunska sonda", "Sonda"], }, shipTypes: { first: "prva", second: "druga", third: "tretja", }, title: { distance: { distance: "Razdalja", coordsDifference: "Razlika v poziciji", galaxy: ["galaksija", "galaksije"], system: ["osončje", "osončij"], positionSetTo16: "Koordinate za pozicijo so vedno nastavljene na 16!", ignoreSystems: "Ignoriraj osončja (prazna/neaktivna)" }, fleetSpeed: { selectedSpeed: "Izbrana hitrost", types: { peaceful: "miroljubna", war: "vojna", holding: "obrambna", }, fleetSpeed: "hitrost.", missionTypesStr: "Misije, ki spadajo pod izbrano hitrost flote", missionTypes: { peaceful: "Ekspedicija, Kolonizacija, Transport, Premik", war: "Recikliraj ruševine, Vohuni, Napad, ACS napad, Uničenje lune", holding: "ACS obramba" }, clickStr: "Kliknite tukaj za preklapljanje med miroljubno/vojno/obrambno hitrostjo" }, briefingSelector: { oneWay: "Izbrano je trajanje leta v eno smer", twoWay: "Izbrano je trajanje leta v obe smeri", arrival: "Izbran je čas prihoda", return: "Izbran je čas vrnitve", clickStr: "Kliknite za preklop med enosmernim ali dvosmernim trajanjem leta in časom prihoda ali vrnitve" }, speedModifier: "Modifikator hitrosti", ship: { selected: "Izbrana", ship: " ladja:", speed: "Hitrost", clickStr: "Kliknite tukaj za spremembo izbrane ladje", warningStr: "POZOR: Hitrost ladje ni posodobljena!\nPojdite na stran Flote, da posodobite vrednosti hitrosti." }, infoBtn: { savedSpeedValues: "Shranjene vrednosti hitrosti", uniSettings: "Nastavitve vesolja", fleetSpeed: "Miroljubna/vojna/obrambna hitrost flote", donut: "Krožna galaksija/osončja", galaxyNum: "Števijo galaksij", ignoreSystems: "Ignoriraj prazna/neaktivna osončja" }, }, }, }; // Add style sheets GM_addStyle(` #GFD_table { width: 100%; height: 24px; } #GFD_distance { cursor: default; padding: 0px 6px; color: ${COLORS.gray} } .GFD_btn { cursor: pointer; height: 16px; padding: 0; border: 1px solid transparent; border-radius: 3px; background-color: transparent; font-family: Verdana, Arial, SunSans-Regular, sans-serif; font-size: 12px; font-weight: bold; color: white; } .GFD_btn:hover { border: 1px solid white; } .GFD_ship { cursor: pointer; width: 142px; height: 16px; padding: 0 6px; border-radius: 3px; background-color: transparent; font-family: Verdana, Arial, SunSans-Regular, sans-serif; font-size: 12px; } .GFD_ship:hover { background-color: #767F8833; } .GFD_shipName { color: ${COLORS.blue}; } #GFD_infoBtn { cursor: default; height: 16px; padding: 0; border: 1px solid transparent; border-radius: 3px; font-family: Verdana, Arial, SunSans-Regular, sans-serif; font-size: 12px; font-weight: normal; color: white; } `); // Assign "pageId" let bodyId = document.getElementsByTagName("body")[0].id; let pageId; if (bodyId == "ingamepage") { pageId = document.getElementsByClassName("maincontent")[0].id; } else { pageId = bodyId; } // Local storage object for speed of all ships const PLAYER_INFO_LOCAL_STORAGE_KEY = "GFD_playerInfo"; const PLAYER_INFO_VERSION = 1; let playerInfo; if (!localStorage.getItem(PLAYER_INFO_LOCAL_STORAGE_KEY)) { // Set and save default "playerInfo" setPlayerInfo(); } else { playerInfo = JSON.parse(localStorage.getItem(PLAYER_INFO_LOCAL_STORAGE_KEY)); // Overwrite "playerInfo" to (new) default structure if a new version is avaiable if (playerInfo.version !== PLAYER_INFO_VERSION) { setPlayerInfo(); } } // Funcitons to set "playerInfo" function setPlayerInfo () { playerInfo = { version: PLAYER_INFO_VERSION, lastUpdate: "", ships: { fighterLight: createShip("204", 12500), fighterHeavy: createShip("205", 10000), cruiser: createShip("206", 15000), battleship: createShip("207", 10000), interceptor: createShip("215", 10000), bomber: createShip("211",5000), destroyer: createShip("213", 5000), deathstar: createShip("214", 100), reaper: createShip("218", 7000), explorer: createShip("219", 12000), transporterSmall: createShip("202", 10000), transporterLarge: createShip("203", 7500), colonyShip: createShip("208", 2500), recycler: createShip("209", 6000), espionageProbe: createShip("210", 100000000), }, } // Log the newly created "playerInfo" object console.log("*** Galaxy Flight Duration ***\n\nplayerInfo (newly created):", playerInfo); // Save "playerInfo" to localStorage localStorage.setItem(PLAYER_INFO_LOCAL_STORAGE_KEY, JSON.stringify(playerInfo)); } // Function to create properties for each ship (inside playerInfo.ships) function createShip (id, speed) { return { id, speed }; } // *** FLEETDISPATCH *** if (pageId == "fleetdispatchcomponent") { // Assign current date from "OGameClock" let ogClock = document.getElementsByClassName("OGameClock")[0].textContent; // Fetch fleet API only once per day if (playerInfo.lastUpdate !== ogClock) { fetchFleetApi(ogClock); } } // Function to fetch fleet API data from window object ("fleetDispatcher.fleetHelper.shipsData") function fetchFleetApi (clock) { // Assign "ogFleetApi" from window object let ogFleetApi = shipsData; // OGame window object. OLD: fleetDispatcher.fleetHelper.shipsData; if (ogFleetApi) { // Save fleet speed from "ogFleetApi" to "playerInfo" saveFleetApi(ogFleetApi); // Assign current date for "lastUpdate" playerInfo.lastUpdate = clock; // Log results let shipsSpeedStr = ""; for (let shipSelector in playerInfo.ships) { let ship = playerInfo.ships[shipSelector]; shipsSpeedStr += "\n " + ship.nameFull + ": " + ship.speed; } console.log("*** Galaxy Flight Duration ***\n\nFLEET API succesfully saved! ("+playerInfo.lastUpdate+")\n\nplayerInfo:", playerInfo); // Save "playerInfo" to localStorage localStorage.setItem(PLAYER_INFO_LOCAL_STORAGE_KEY, JSON.stringify(playerInfo)); } else { console.error("*** Galaxy Flight Duration ***\n\nERROR: fleet API was not fetched!"); } } // Function to save fleet speed from "ogFleetApi" to "playerInfo" function saveFleetApi (ogFleetApi) { for (let shipSelector in playerInfo.ships) { let ship = playerInfo.ships[shipSelector]; ship.speed = ogFleetApi[ship.id].speed; } } // Possible setitngs that a player can choose const settings = { fleetSpeedType: ["peaceful", "war", "holding"], briefingSelector: ["oneWay", "twoWay", "arrival", "return"], speedModifier: [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], speedModifierGeneral: [1, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1, 0.05], firstShip: ["fighterLight", "fighterHeavy", "cruiser", "battleship", "interceptor", "bomber", "destroyer", "deathstar", "reaper", "explorer", "transporterSmall", "transporterLarge", "colonyShip", "recycler", "espionageProbe"], secondShip: ["fighterLight", "fighterHeavy", "cruiser", "battleship", "interceptor", "bomber", "destroyer", "deathstar", "reaper", "explorer", "transporterSmall", "transporterLarge", "colonyShip", "recycler", "espionageProbe"], thirdShip: ["fighterLight", "fighterHeavy", "cruiser", "battleship", "interceptor", "bomber", "destroyer", "deathstar", "reaper", "explorer", "transporterSmall", "transporterLarge", "colonyShip", "recycler", "espionageProbe"], }; // Local storage object for player settings (if it does not exist, create one) const PLAYER_SETTINGS_LOCAL_STORAGE_KEY = "GFD_playerSettings"; const PLAYER_SETTINGS_VERSION = 1.5; let playerSettings; if (!localStorage.getItem(PLAYER_SETTINGS_LOCAL_STORAGE_KEY)) { // Set and save default "playerSettings" setPlayerSettings(); } else { playerSettings = JSON.parse(localStorage.getItem(PLAYER_SETTINGS_LOCAL_STORAGE_KEY)); // OverWrite "playerSettings" to (new) default structure if a new version is avaiable if (playerSettings.version !== PLAYER_SETTINGS_VERSION) { setPlayerSettings(); } } // Function to set "playerSettings" function setPlayerSettings () { playerSettings = { version: PLAYER_SETTINGS_VERSION, indexOf: { fleetSpeedType: 1, // Index of "settings.fleetSpeedType". briefingSelector: 0, // Index of "settings.briefingSelector". speedModifier: 0, // Index of "settings.speedModifier". firstShip: 0, // Index of "settings.firstShip". secondShip: 0, // Index of "settings.secondShip". thirdShip: 0, // Index of "settings.thirdShip". }, }; // Log newly crated "playerSettings" object console.log("*** Galaxy Flight Duration ***\n\nsettings:", settings, "\n\nplayerSettings (newly created):", playerSettings); savePlayerSettings(); } // Function to save "playerSettings to localStorage function savePlayerSettings () { localStorage.setItem(PLAYER_SETTINGS_LOCAL_STORAGE_KEY, JSON.stringify(playerSettings)); } // *** GALAXY *** if (pageId == "galaxycomponent") { // Assign meta information from OGame meta tag const metaInfo = { fleetSpeed: { peaceful: parseInt(document.querySelector("meta[name=ogame-universe-speed-fleet-peaceful]").content, 10), war: parseInt(document.querySelector("meta[name=ogame-universe-speed-fleet-war]").content, 10), holding: parseInt(document.querySelector("meta[name=ogame-universe-speed-fleet-holding]").content, 10), }, donut: { galaxy: parseInt(document.querySelector("meta[name=ogame-donut-galaxy]").content, 10), system: parseInt(document.querySelector("meta[name=ogame-donut-system]").content, 10), }, planetCoords: document.querySelector("meta[name=ogame-planet-coordinates]").content, }; // Assign player classs const playerClass = document.getElementById("characterclass").getElementsByClassName("sprite characterclass")[0].className.split(" ").pop(); // General class = "warrior". // Assign (user selected) language from cookies const cookieMatch = document.cookie.match(/oglocale=([^;]+)/); let lang = cookieMatch ? cookieMatch[1] : "en"; // Set language to english ("en") if (user selected) language is not supported (not in "LOCALES") if (!LOCALES[lang]) { lang = "en"; } //console.log("*** Galaxy Flight Duration ***\n\nSelected language: \"" + lang + "\""); // Function to calculate DIFFERENCE IN POSITION function calcCoordsDifference (takeOffGalaxy, takeOffSystem, takeOffPosition, destinationGalaxy, destinationSystem, destinationPosition, maxNumberOfGalaxies, donutSystem, donutGalaxy) { // If destination is on the SAME LOCATION as take-off location if (takeOffGalaxy == destinationGalaxy && takeOffSystem == destinationSystem && takeOffPosition == destinationPosition) { return { g: 0, s: 0, p: 0 }; } // ... else, if destination is in the SAME SYSTEM as take-off location else if (takeOffGalaxy == destinationGalaxy && takeOffSystem == destinationSystem) { let positionX = Math.abs(destinationPosition - takeOffPosition); return { g: 0, s: 0, p: positionX }; } // ... else, if destination is in the SAME GALAXY as take-off location else if (takeOffGalaxy == destinationGalaxy) { let systemX = Math.abs(destinationSystem - takeOffSystem); let system499minusX = 499 - systemX; let minSystemX = Math.min(systemX, system499minusX); if (donutSystem == 1) { return { g: 0, s: minSystemX, p: 0 }; } else if (donutSystem == 0) { return { g: 0, s: systemX, p: 0 }; } } // else, destination is NOT in the same galaxy as take-off location else { let galaxyX = Math.abs(destinationGalaxy - takeOffGalaxy); let galaxyMaxMinusX = maxNumberOfGalaxies - galaxyX; let minGalaxyX = Math.min(galaxyX, galaxyMaxMinusX); if (donutGalaxy == 1) { return { g: minGalaxyX, s: 0, p: 0 }; } else if (donutGalaxy == 0) { return { g: galaxyX, s: 0, p: 0 }; } } } // Function to calculate DISTANCE function calcDistance (coordsDifference) { // If difference in position is [0:0:0] if (coordsDifference.g == 0 && coordsDifference.s == 0 && coordsDifference.p == 0) { return 5; } // ... else, if difference in position is [0:0:x] else if (coordsDifference.g == 0 && coordsDifference.s == 0) { return 1000 + 5 * coordsDifference.p; } // ... else, if difference in position [0:x:y] else if (coordsDifference.g == 0) { return 2700 + 95 * coordsDifference.s; } // else, if difference in position is [x:y:z] else { return 20000 * coordsDifference.g; } } // Function to calculate FLIGHT DURATION in seconds, i.e. "toSeconds" function calcFlightDuration (oneOrTwoWay, distance, speedShip, speedModifier, serverFleetSpeed) { return Math.round(((10 + (3500 / speedModifier) * Math.sqrt((10 * distance) / speedShip)) / serverFleetSpeed) * oneOrTwoWay); } // Function to format time duration into a string (e.g. "2:09:09h") function formatFlightDurationTime (flightDurationToSeconds) { // Calculate "seconds", "minutes", and "hours" from "toSeconds" let hours = Math.floor(flightDurationToSeconds / 3600); let minutes = (Math.floor(flightDurationToSeconds / 60)) % 60; let seconds = flightDurationToSeconds % 60; // Format "hours", "minutes", and "seconds" into one string let formatedFlightDuration = `${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}h`; return formatedFlightDuration; } // Function to calculate and format ARRIVAL or RETURN time function formatArrivalReturnTime (flightDurationToSeconds) { // Get the current time from "OGameClock" const ogClockTimeStr = document.getElementsByClassName("OGameClock")[0].getElementsByTagName("span")[0].textContent; // Parse the time string to extract hours, minutes, and seconds const ogClockTime = ogClockTimeStr.split(":"); let hours = parseInt(ogClockTime[0], 10); let minutes = parseInt(ogClockTime[1], 10); let seconds = parseInt(ogClockTime[2], 10); // Add flight duration [seconds] seconds += flightDurationToSeconds; // Ensure that SECONDS do not spill over 60 and add extra minutes (from seconds) minutes += Math.floor(seconds / 60); seconds %= 60; // Ensure that MINUTES do not spill over 60 and add extra hours (from minutes) hours += Math.floor(minutes / 60); minutes %= 60; // Ensure that HOURS do not spill over 24 (this is not the case for flightDuration that can potentially be over 24h, see: "formatFlightDurationTime") hours %= 24; // Format "hours", "minutes", and "seconds" into one string const formattedArrivalReturnTimeStr = `${hours < 10 ? '0' : ''}${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; return formattedArrivalReturnTimeStr; } // Assign co-ordinates for ACTIVE planet let coordsPlanetSplit = metaInfo.planetCoords.split(":"); const coordsPlanet = { g: parseInt(coordsPlanetSplit[0], 10), s: parseInt(coordsPlanetSplit[1], 10), p: parseInt(coordsPlanetSplit[2], 10), }; // Assign co-ordinates selected inside galaxy view const galaxyView = { g: 0, s: 0, p: 16, // Position is always set to 16. }; // Function to assign "galaxyView" function assignGalaxyView () { galaxyView.g = parseInt(document.getElementById("galaxy_input").value, 10); galaxyView.s = parseInt(document.getElementById("system_input").value, 10); } // Function to display new div element function displayDiv () { // Query selector for OGame parent element let ogParent = document.querySelector("#galaxyContent > div"); // Create new div element and append it to parent (OGame) element let div = document.createElement("div"); div.id = "GFD"; div.className = "galaxyRow ctGalaxyFooter"; ogParent.appendChild(div); // InnerHTML of new div element: div.innerHTML = ` <table id="GFD_table"> <tbody><tr> <td width="64px"> <span id="GFD_distance"></span> </td> <td width="32px"> <button id="GFD_fleetSpeedType" class="GFD_btn" style="width: 28px"></button> </td> <td width="32px"> <button id="GFD_briefingSelector" class="GFD_btn" style="width: 28px; font-size: 10px"></button> </td> <td width="54px"> <button id="GFD_speedModifier" class="GFD_btn" style="width: 50px; height: 18px; background-color: transparent"></button> </td> <td> <button id="GFD_firstShip" class="GFD_ship"> <span id="GFD_firstShip_name" class="GFD_shipName"></span> <span id="GFD_firstShip_flightBriefing"></span> </button> </td> <td> <button id="GFD_secondShip" class="GFD_ship"> <span id="GFD_secondShip_name" class="GFD_shipName"></span> <span id="GFD_secondShip_flightBriefing"></span> </button> </td> <td> <button id="GFD_thirdShip" class="GFD_ship"> <span id="GFD_thirdShip_name" class="GFD_shipName"></span> <span id="GFD_thirdShip_flightBriefing"></span> </button> </td> <td width="26px"> <button id="GFD_infoBtn" class="GFD_btn" style="width: 16px; background-color: ${COLORS.blue}"></button> </td> </tr></tbody> </table> `; } // Master function to update elements in div function updateDiv () { if (ignoreSystemsCheck == true) { updateDivIgnoreSystems(); } else { updateDivDefault(); } } // Declare "checkTargetData" (so it is undefined for "updateDistance(checkTargetData)" inside "updateDivDefault()") let checkTargetData; // Function to update elements in div function updateDivDefault () { // DISTANCE (and DIFFERENCE IN POSITION) let distance = updateDistance(checkTargetData); // FLEET SPEED TYPE (peaceful/war/holding) let fleetSpeed = updateFleetSpeedType(); // Fleet BRIEFING (ONE/TWO WAY flight duration or ARRIVAL/RETURN time) let briefingSelector = updateBriefingSelector(); // SPEED MODIFIER let speedModifier = updateSpeedModifier(); // SHIPS updateShip("first", briefingSelector, distance, speedModifier, fleetSpeed); updateShip("second", briefingSelector, distance, speedModifier, fleetSpeed); updateShip("third", briefingSelector, distance, speedModifier, fleetSpeed); // INFO BUTTON updateInfoBtn(); } // Function to update elements in div only on servers with "Ignore systems" settings async function updateDivIgnoreSystems () { // Function to call "checkTarget" async function callCheckTarget(g, s, p) { const response = await fetch("/game/index.php?page=ingame&component=fleetdispatch&action=checkTarget&ajax=1&asJson=1", { "headers": { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "x-requested-with": "XMLHttpRequest" }, "body": `am208=1&galaxy=${g}&system=${s}&position=${p}&type=1&token=${token}&union=0`, // OGame window object. "method": "POST", }); checkTargetData = await response.json(); // Assign new token let newToken = checkTargetData.newAjaxToken; window.token = newToken; updateOverlayToken("phalanxDialog", newToken); // To update the token for the phalanx of a single planet. updateOverlayToken("phalanxSystemDialog", newToken); // To update the token for the system phalanx (Warriors alliance class feature). //console.log("*** Galaxy Flight Duration ***\n\ncheckTargetData:", checkTargetData, "\n\ncheckTargetData.status: \""+checkTargetData.status+"\"\n\ncheckTargetData.emptySystems:", checkTargetData.emptySystems, "\ncheckTargetData.inactiveSystems", checkTargetData.inactiveSystems, "\n\nNew token:", checkTargetData.newAjaxToken); return checkTargetData; } // Call function callCheckTarget(galaxyView.g, galaxyView.s, galaxyView.p) .then(checkTargetData => { // DISTANCE (and DIFFERENCE IN POSITION) let distance = updateDistance(checkTargetData); // FLEET SPEED TYPE (peaceful/war/holding) let fleetSpeed = updateFleetSpeedType(); // Fleet BRIEFING (ONE/TWO WAY flight duration or ARRIVAL/RETURN time) let briefingSelector = updateBriefingSelector(); // SPEED MODIFIER let speedModifier = updateSpeedModifier(); // SHIPS updateShip("first", briefingSelector, distance, speedModifier, fleetSpeed); updateShip("second", briefingSelector, distance, speedModifier, fleetSpeed); updateShip("third", briefingSelector, distance, speedModifier, fleetSpeed); // INFO BUTTON updateInfoBtn(); }).catch(error => { console.error("*** Galaxy Flight Duration ***\n\nError in updateDivIgnoreSystems():", error); }); } // Function for DISTANCE (and DIFFERENCE IN POSITION) function updateDistance (checkTargetData) { // Distance calculation for universes with "Ignore Systems" settings if (checkTargetData && ignoreSystemsCheck == true) { // Assign "ignoreSystems" let ignoreSystems = { empty: checkTargetData.emptySystems ? checkTargetData.emptySystems : 0, inactive: checkTargetData.inactiveSystems ? checkTargetData.inactiveSystems : 0, sum: 0, }; // Calculate sum of "empty" and "inactive" systems ignoreSystems.sum = ignoreSystems.empty + ignoreSystems.inactive; // Calculate new DIFFERENCE IN POSITION and DISTANCE let coordsDifference = calcCoordsDifference (coordsPlanet.g, coordsPlanet.s, coordsPlanet.p, galaxyView.g, galaxyView.s, galaxyView.p, serverData.galaxyNum, metaInfo.donut.system, metaInfo.donut.galaxy); let newCoordsDifference = Object.assign({}, coordsDifference); // Create deep copy. newCoordsDifference.s = coordsDifference.s - ignoreSystems.sum; let distance = calcDistance (newCoordsDifference); let distanceSpan = document.getElementById("GFD_distance"); distanceSpan.innerHTML = distance; if (distance >= 20000) { distanceSpan.style.color = COLORS.red; } else if (ignoreSystems.sum > 0) { distanceSpan.style.color = COLORS.green; } else { distanceSpan.style.color = COLORS.gray; } // Title let coordsDifferenceTitleStr; if (newCoordsDifference.g > 0) { coordsDifferenceTitleStr = newCoordsDifference.g == 1 ? newCoordsDifference.g+" "+LOCALES[lang].title.distance.galaxy[0] : newCoordsDifference.g+" "+LOCALES[lang].title.distance.galaxy[1]; } else if (newCoordsDifference.s == 0) { coordsDifferenceTitleStr = newCoordsDifference.s+" "+LOCALES[lang].title.distance.system[1] + "\n\n" + LOCALES[lang].title.distance.positionSetTo16; } else { coordsDifferenceTitleStr = newCoordsDifference.s == 1 ? newCoordsDifference.s+" ("+coordsDifference.s+") "+LOCALES[lang].title.distance.system[0] : newCoordsDifference.s+" ("+coordsDifference.s+") "+LOCALES[lang].title.distance.system[1]; } distanceSpan.title = LOCALES[lang].title.distance.distance+": "+distance + "\n" + LOCALES[lang].title.distance.coordsDifference+": "+coordsDifferenceTitleStr + "\n\n" + LOCALES[lang].title.distance.ignoreSystems+": "+ignoreSystems.sum+" ("+ignoreSystems.empty+" / "+ignoreSystems.inactive+")"; return distance; } // ... distance calculation for default universes else { let coordsDifference = calcCoordsDifference (coordsPlanet.g, coordsPlanet.s, coordsPlanet.p, galaxyView.g, galaxyView.s, galaxyView.p, serverData.galaxyNum, metaInfo.donut.system, metaInfo.donut.galaxy); let distance = calcDistance (coordsDifference); let distanceSpan = document.getElementById("GFD_distance"); distanceSpan.innerHTML = distance; distanceSpan.style.color = distance >= 20000 ? COLORS.red : COLORS.gray; // Title let coordsDifferenceTitleStr; if (coordsDifference.g > 0) { coordsDifferenceTitleStr = coordsDifference.g == 1 ? coordsDifference.g+" "+LOCALES[lang].title.distance.galaxy[0] : coordsDifference.g+" "+LOCALES[lang].title.distance.galaxy[1]; } else if (coordsDifference.s == 0) { coordsDifferenceTitleStr = coordsDifference.s+" "+LOCALES[lang].title.distance.system[1] + "\n\n" + LOCALES[lang].title.distance.positionSetTo16; } else { coordsDifferenceTitleStr = coordsDifference.s == 1 ? coordsDifference.s+" "+LOCALES[lang].title.distance.system[0] : coordsDifference.s+" "+LOCALES[lang].title.distance.system[1]; } distanceSpan.title = LOCALES[lang].title.distance.distance+": "+distance + "\n" + LOCALES[lang].title.distance.coordsDifference+": "+coordsDifferenceTitleStr; return distance; } } // Funciton for FLEET SPEED TYPE (peaceful/war/holding) function updateFleetSpeedType () { let fleetSpeedType = settings.fleetSpeedType[playerSettings.indexOf.fleetSpeedType]; let fleetSpeed = metaInfo.fleetSpeed[fleetSpeedType]; let fleetSpeedTypeSpan = document.getElementById("GFD_fleetSpeedType"); fleetSpeedTypeSpan.innerHTML = "x" + fleetSpeed; fleetSpeedTypeSpan.title = LOCALES[lang].title.fleetSpeed.selectedSpeed+": "+LOCALES[lang].title.fleetSpeed.types[fleetSpeedType]+" "+LOCALES[lang].title.fleetSpeed.fleetSpeed+"\n\n" + LOCALES[lang].title.fleetSpeed.missionTypesStr+":\n" + LOCALES[lang].title.fleetSpeed.missionTypes[fleetSpeedType] + "\n\n("+LOCALES[lang].title.fleetSpeed.clickStr+".)"; fleetSpeedTypeSpan.style.backgroundColor = COLORS.fleetSpeedType[playerSettings.indexOf.fleetSpeedType]; // Right click fleetSpeedTypeSpan.onclick = function () { playerSettings.indexOf.fleetSpeedType = (playerSettings.indexOf.fleetSpeedType + 1) % settings.fleetSpeedType.length; updateDivDefault(); savePlayerSettings(); }; // Left click fleetSpeedTypeSpan.oncontextmenu = (event) => { event.preventDefault(); // Prevents the default context menu from showing up. playerSettings.indexOf.fleetSpeedType = (playerSettings.indexOf.fleetSpeedType - 1 + settings.fleetSpeedType.length) % settings.fleetSpeedType.length; updateDivDefault(); savePlayerSettings(); } // Return selected "fleetSpeed" value for "updateShip" function return fleetSpeed; } // Function for fleet BRIEFING (ONE/TWO WAY flight duration or ARRIVAL/RETURN time) function updateBriefingSelector () { let briefingSelector = settings.briefingSelector[playerSettings.indexOf.briefingSelector]; let briefingSelectorSpan = document.getElementById("GFD_briefingSelector"); // Determine ICON of the button based on the "playerSettings" const briefingSelectorIcons = { oneWay: ">", twoWay: "<", arrival: ">|", return: "|<" }; let briefingSelectorInnerHTML = briefingSelectorIcons[briefingSelector]; briefingSelectorSpan.innerHTML = briefingSelectorInnerHTML; // Deterine TITLE of the button const briefingSelectorTitles = { oneWay: LOCALES[lang].title.briefingSelector.oneWay + ".\n\n(" + LOCALES[lang].title.briefingSelector.clickStr + ".)", twoWay: LOCALES[lang].title.briefingSelector.twoWay + ".\n\n(" + LOCALES[lang].title.briefingSelector.clickStr + ".)", arrival: LOCALES[lang].title.briefingSelector.arrival + ".\n\n(" + LOCALES[lang].title.briefingSelector.clickStr + ".)", return: LOCALES[lang].title.briefingSelector.return + ".\n\n(" + LOCALES[lang].title.briefingSelector.clickStr + ".)", }; briefingSelectorSpan.title = briefingSelectorTitles[briefingSelector]; // Determine BACKGROUND COLOR of the button briefingSelectorSpan.style.backgroundColor = COLORS.briefingSelector[playerSettings.indexOf.briefingSelector]; // Right click briefingSelectorSpan.onclick = function () { playerSettings.indexOf.briefingSelector = (playerSettings.indexOf.briefingSelector + 1) % settings.briefingSelector.length; updateDivDefault(); savePlayerSettings(); } // Left click briefingSelectorSpan.oncontextmenu = (event) => { event.preventDefault(); // Prevents the default context menu from showing up. playerSettings.indexOf.briefingSelector = (playerSettings.indexOf.briefingSelector - 1 + settings.briefingSelector.length) % settings.briefingSelector.length; updateDivDefault(); savePlayerSettings(); } // Return selected "briefingSelector" for "updateShip" function return briefingSelector; } // Function for SPEED MODIFIER function updateSpeedModifier () { let speedModifierSpan = document.getElementById("GFD_speedModifier"); speedModifierSpan.title = LOCALES[lang].title.speedModifier; let speedModifier; // If General class is active if (playerClass == "warrior") { speedModifier = settings.speedModifierGeneral[playerSettings.indexOf.speedModifier]; speedModifierSpan.innerHTML = Math.round(speedModifier * 100) + "%"; speedModifierSpan.style.color = COLORS.speedModifierGeneral[playerSettings.indexOf.speedModifier]; // Right click (-5%) speedModifierSpan.onclick = function () { playerSettings.indexOf.speedModifier = (playerSettings.indexOf.speedModifier + 1) % settings.speedModifierGeneral.length; updateDivDefault(); savePlayerSettings } // Left-click (+5%) speedModifierSpan.oncontextmenu = (event) => { event.preventDefault(); // Prevents the default context menu from showing up. playerSettings.indexOf.speedModifier = (playerSettings.indexOf.speedModifier - 1 + settings.speedModifierGeneral.length) % settings.speedModifierGeneral.length; updateDivDefault(); savePlayerSettings(); } } // ... else, if every other class is active else { // In case a player deactivates General class and leaves "playerSettings.indexOf.speedModifier" saved to value that is bigger than 9 (i.e. saved speed modifier from 50% to 5%) set "playerSettings.indexOf.speedModifier" back to default value, 0 (i.e. 100% speed modifier) playerSettings.indexOf.speedModifier = playerSettings.indexOf.speedModifier > 9 ? playerSettings.indexOf.speedModifier = 0 : playerSettings.indexOf.speedModifier; speedModifier = settings.speedModifier[playerSettings.indexOf.speedModifier]; speedModifierSpan.innerHTML = Math.round(speedModifier * 100) + "%"; speedModifierSpan.style.color = COLORS.speedModifier[playerSettings.indexOf.speedModifier]; // Right click (-10%) speedModifierSpan.onclick = function () { playerSettings.indexOf.speedModifier = (playerSettings.indexOf.speedModifier + 1) % settings.speedModifier.length; updateDivDefault(); savePlayerSettings(); } // Left-click (+10%) speedModifierSpan.oncontextmenu = (event) => { event.preventDefault(); // Prevents the default context menu from showing up. playerSettings.indexOf.speedModifier = (playerSettings.indexOf.speedModifier - 1 + settings.speedModifier.length) % settings.speedModifier.length; updateDivDefault(); savePlayerSettings(); } } // Return selected "speedModifier" value for "updateShip" function return speedModifier; } // Function for SHIPS function updateShip (shipType, briefingSelector, distance, speedModifier, fleetSpeed) { // Assign selectors for other variables let settingsSelector = `${shipType}Ship`; let shipSelector = settings[settingsSelector][playerSettings.indexOf[settingsSelector]]; // Calculate flight duration [seconds] let speed = playerInfo.ships[shipSelector].speed; const oneOrTwoWay = { oneWay: 1, twoWay: 2, arrival: 1, return: 2 }; let flightDurationToSeconds = calcFlightDuration(oneOrTwoWay[briefingSelector], distance, speed, speedModifier, fleetSpeed); // Assign ship name and formated flight duration let shipInfo = { name: LOCALES[lang].ships[shipSelector][1], flightBriefing: ( briefingSelector == "oneWay" || briefingSelector == "twoWay" ) ? formatFlightDurationTime(flightDurationToSeconds) : formatArrivalReturnTime(flightDurationToSeconds), }; // Assign variables from div element and updete its values let shipDiv = document.getElementById(`GFD_${shipType}Ship`); let shipSpan = { name: document.getElementById(`GFD_${shipType}Ship_name`), flightBriefing: document.getElementById(`GFD_${shipType}Ship_flightBriefing`), }; shipSpan.name.innerHTML = shipInfo.name+": "; shipSpan.flightBriefing.innerHTML = shipInfo.flightBriefing; // Assign title let shipTitle = `${LOCALES[lang].title.ship.selected} ${LOCALES[lang].shipTypes[shipType]}${LOCALES[lang].title.ship.ship} ${LOCALES[lang].ships[shipSelector][0]}\n${LOCALES[lang].title.ship.speed}: ${speed}\n\n(${LOCALES[lang].title.ship.clickStr}.)`; if (playerInfo.lastUpdate == "") { shipDiv.title = LOCALES[lang].title.ship.warningStr; shipSpan.flightBriefing.style.color = COLORS.red; } else { shipDiv.title = shipTitle; shipSpan.flightBriefing.style.color = oneOrTwoWay[briefingSelector] == 1 ? "white" : COLORS.gray; } // Left-click (next ship) shipDiv.onclick = function () { playerSettings.indexOf[settingsSelector] = (playerSettings.indexOf[settingsSelector] + 1) % settings[settingsSelector].length; updateDivDefault(); savePlayerSettings(); }; // Right click (previous ship) shipDiv.oncontextmenu = (event) => { event.preventDefault(); // Prevents the default context menu from showing up. playerSettings.indexOf[settingsSelector] = (playerSettings.indexOf[settingsSelector] - 1 + settings[settingsSelector].length) % settings[settingsSelector].length; updateDivDefault(); savePlayerSettings(); } // Activate mutation observer for OGame clock if "briefingSelector" is set to "arrival" or "return" and deactivate this observer if "briefingSelector" is set to "oneWay" or "twoWay" if (briefingSelector == "arrival" || briefingSelector == "return") { startObserver_ogClock(); } else { stopObserver_ogClock(); } } // Function for INFO BUTTON function updateInfoBtn () { let infoBtnSpan = document.getElementById("GFD_infoBtn"); infoBtnSpan.innerHTML = "i"; // Title that contains all saved speeds from all ships (with date they were last updated) and universe/server meta data let titleStr = LOCALES[lang].title.infoBtn.savedSpeedValues+" ("+playerInfo.lastUpdate+"):\n\n"; for (let shipSelector in playerInfo.ships) { if (playerInfo.ships.hasOwnProperty(shipSelector)) { titleStr += LOCALES[lang].ships[shipSelector][0]+": "+playerInfo.ships[shipSelector].speed+"\n"; } } titleStr += "\n\n" + LOCALES[lang].title.infoBtn.uniSettings+":\n\n" + LOCALES[lang].title.infoBtn.fleetSpeed+": x"+metaInfo.fleetSpeed.peaceful+" / x"+metaInfo.fleetSpeed.war+" / x"+metaInfo.fleetSpeed.holding + "\n" + LOCALES[lang].title.infoBtn.donut+": "+metaInfo.donut.galaxy+" / "+metaInfo.donut.system + "\n" + LOCALES[lang].title.infoBtn.galaxyNum+": "+serverData.galaxyNum + "\n" + LOCALES[lang].title.infoBtn.ignoreSystems+": "+serverData.fleetIgnoreEmptySystems+" / "+serverData.fleetIgnoreInactiveSystems; infoBtnSpan.title = titleStr; } // *** OGAME CLOCK MUTATION OBSERVER *** // Boolean variable to track the observer state let observe_ogClockIsActive = true; // Callback function to execute when mutations are observed function handleMutation_ogClock (mutationsList, observer) { // Check if the observer is active if (observe_ogClockIsActive) { // Call functions updateDiv(); } }; // Create a MutationObserver instance const observe_ogClock = new MutationObserver(handleMutation_ogClock); // Select the target node const ogClock = document.getElementsByClassName("OGameClock")[0]; // Function to toggle the observer state function toggleObserver_ogClock () { observe_ogClockIsActive = !observe_ogClockIsActive; } // Function to start observing the target node for configured mutations function startObserver_ogClock () { observe_ogClock.observe(ogClock, { childList: true, subtree: true }); } // Function to stop observing mutations function stopObserver_ogClock () { observe_ogClock.disconnect(); } // *** GALAXY VIEW MUTATION OBSERVER *** // Variable to store the previous state of "galaxyLoading" let prevGalaxyLoading = ""; // Function to handle the mutation event function handleMutation_galaxyView (mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === "attributes" && mutation.attributeName === "style") { // Assign display state of OGame loading GIF let galaxyLoading = document.querySelector("#galaxyLoading").style.display; // Check for change from "" to "none" in "galaxyLoading" (".style.display") if (prevGalaxyLoading === "" && galaxyLoading === "none") { // Call functions assignGalaxyView(); updateDiv(); } // Update the previous state prevGalaxyLoading = galaxyLoading; } } } // Create a MutationObserver with the handleMutation callback const observer_galaxyView = new MutationObserver(handleMutation_galaxyView); // Observe changes in the target node const galaxyLoadingDiv = document.querySelector("#galaxyLoading"); observer_galaxyView.observe(galaxyLoadingDiv, { attributes: true }); // Call functions assignGalaxyView(); displayDiv(); updateDiv(); }