GeoGuessr XP FARM - The Best Cheat Out There!

Introducing Exodus: One of the greatest geoguessr scripts out there able to farm xp very fast to precise location pinpointing + an whole new overlay to the site! this script will amaze you!

目前为 2024-04-19 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GeoGuessr XP FARM - The Best Cheat Out There!
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.8
  5. // @description Introducing Exodus: One of the greatest geoguessr scripts out there able to farm xp very fast to precise location pinpointing + an whole new overlay to the site! this script will amaze you!
  6. // @author ems
  7. // @match https://www.geoguessr.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
  9. // @run-at document-start
  10. // @require https://gf.qytechs.cn/scripts/460322-geoguessr-styles-scan/code/Geoguessr%20Styles%20Scan.js?version=1246943
  11. // @grant GM_xmlhttpRequest
  12.  
  13.  
  14.  
  15.  
  16. // ==/UserScript==
  17.  
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. // Create and inject the logo HTML and CSS
  23. function createLogo() {
  24. const logoHTML = `
  25. <div id="exodusLogo" class="logo">Version v3.8 [BETA]</div>
  26. `;
  27.  
  28. const logoCSS = `
  29. .logo {
  30. font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  31. font-size: 18px; /* Smaller font size */
  32. color: transparent; /* Hide the text initially */
  33. text-shadow: 0 0 5px rgba(255, 0, 0, 0.8), 0 0 10px rgba(255, 0, 0, 0.8); /* Red text shadow */
  34. background: linear-gradient(45deg, rgba(255, 0, 0, 0.8), rgba(0, 0, 0, 0.8)); /* Gradient from red to black */
  35. background-clip: text; /* Apply the background to the text only */
  36. -webkit-background-clip: text; /* For Safari */
  37. position: fixed;
  38. top: 20px;
  39. left: 25px;
  40. z-index: 9999;
  41. animation: pulse 1s ease-in-out infinite alternate;
  42. }
  43.  
  44. @keyframes pulse {
  45. 0% { transform: scale(1); }
  46. 100% { transform: scale(1.1); }
  47. }
  48. `;
  49.  
  50. // Inject the logo HTML
  51. const logoContainer = document.createElement('div');
  52. logoContainer.innerHTML = logoHTML;
  53. document.body.appendChild(logoContainer);
  54.  
  55. // Inject the logo CSS
  56. const style = document.createElement('style');
  57. style.textContent = logoCSS;
  58. document.head.appendChild(style);
  59. }
  60.  
  61. // Call the function to create the logo
  62. createLogo();
  63.  
  64.  
  65. /////////////////CHECKS IF USER IS BANNED ON PROFILE///////////////////////////
  66. function checkURL() {
  67. if (location.pathname.includes("/user") || location.pathname.includes("/me/profile")) return 1;
  68. return 0;
  69. }
  70.  
  71. function insertAfter(newNode, existingNode) {
  72. existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
  73. }
  74.  
  75. async function checkUser(profileId) {
  76. return fetch(location.origin + "/api/v3/users/" + profileId)
  77. .then(out => out.json())
  78. .catch(err => {console.log(err); return null;});
  79. }
  80.  
  81. let observer = new MutationObserver(() => {
  82. if (checkURL() == 1) {
  83. const profileLink = (location.pathname.includes("/me/profile")) ? document.querySelector('[name="copy-link"]').value : location.href;
  84. const profileId = profileLink.substr(profileLink.lastIndexOf("/") + 1);
  85. checkUser(profileId).then(user => {
  86. if (user !== null) {
  87. if (user.isBanned === false) {
  88. if (document.getElementById("isBanned") == null) {
  89. let proDiv = document.querySelector("[class*='profile-header_accountInfoWrapper__D_iCA']");
  90. let baseDiv = (proDiv) ? proDiv.firstChild : document.querySelector("[data-qa='user-card-title']");
  91. let bannedDiv = document.createElement("div");
  92. bannedDiv.innerHTML = `<div id="isBanned"></div>`;
  93. if (proDiv) {
  94. baseDiv.style = "display: inline-block; margin-right: 10px";
  95. bannedDiv.style.display = "inline-block";
  96. }
  97. insertAfter(bannedDiv, baseDiv);
  98. }
  99. if (document.getElementById("isBanned").innerText !== `Not Banned`) {
  100. document.getElementById("isBanned").innerText = `Not Banned`;
  101. }
  102. } else {
  103. if (document.getElementById("isBanned") == null) {
  104. let proDiv = document.querySelector("[class*='profile-header_accountInfoWrapper__D_iCA']");
  105. let baseDiv = (proDiv) ? proDiv.firstChild : document.querySelector("[data-qa='user-card-title']");
  106. let bannedDiv = document.createElement("div");
  107. bannedDiv.innerHTML = `<div id="isBanned"></div>`;
  108. if (proDiv) {
  109. baseDiv.style = "display: inline-block; margin-right: 10px";
  110. bannedDiv.style.display = "inline-block";
  111. }
  112. insertAfter(bannedDiv, baseDiv);
  113. }
  114. if (document.getElementById("isBanned").innerText !== `User is banned. RIP XD`) {
  115. document.getElementById("isBanned").innerText = `User is banned. RIP XD`;
  116. }
  117. }
  118. }
  119. });
  120. }
  121. });
  122.  
  123. observer.observe(document.body, { subtree: true, childList: true });
  124.  
  125.  
  126.  
  127. // Observer logic remains the same
  128.  
  129. // Function to periodically check and update user's ban status
  130. function checkAndUpdateStatus() {
  131. const profileLink = (location.pathname.includes("/me/profile")) ? document.querySelector('[name="copy-link"]').value : location.href;
  132. const profileId = profileLink.substr(profileLink.lastIndexOf("/") + 1);
  133. checkUser(profileId).then(user => {
  134. if (user !== null) {
  135. if (user.isBanned === false) {
  136. if (document.getElementById("isBanned").innerText !== `Not Banned`) {
  137. document.getElementById("isBanned").innerText = `Not Banned`;
  138. }
  139. } else {
  140. if (document.getElementById("isBanned").innerText !== `User is banned. RIP XD`) {
  141. document.getElementById("isBanned").innerText = `User is banned. RIP XD`;
  142. location.replace(location.href.split('#')[0]); // Reload the page without a full refresh
  143. }
  144. }
  145. }
  146. });
  147. }
  148.  
  149. //////////////////////END////////////////////////////////////
  150.  
  151.  
  152. })();
  153.  
  154.  
  155. let globalCoordinates = {
  156. lat: 0,
  157. lng: 0
  158. };
  159.  
  160. let globalPanoID = undefined;
  161.  
  162. var originalOpen = XMLHttpRequest.prototype.open;
  163. XMLHttpRequest.prototype.open = function(method, url) {
  164. if (url.startsWith('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata')) {
  165. this.addEventListener('load', function () {
  166. let interceptedResult = this.responseText;
  167. const pattern = /-?\d+\.\d+,-?\d+\.\d+/g;
  168. let match = interceptedResult.match(pattern)[0];
  169. let split = match.split(",");
  170. let lat = Number.parseFloat(split[0]);
  171. let lng = Number.parseFloat(split[1]);
  172. globalCoordinates.lat = lat;
  173. globalCoordinates.lng = lng;
  174. });
  175. }
  176. return originalOpen.apply(this, arguments);
  177. };
  178.  
  179. function placeMarker(safeMode){
  180. let {lat,lng} = globalCoordinates;
  181.  
  182. if (safeMode) {
  183. const sway = [Math.random() > 0.5, Math.random() > 0.5];
  184. const multiplier = Math.random() * 4;
  185. const horizontalAmount = Math.random() * multiplier;
  186. const verticalAmount = Math.random() * multiplier;
  187. sway[0] ? lat += verticalAmount : lat -= verticalAmount;
  188. sway[1] ? lng += horizontalAmount : lat -= horizontalAmount;
  189. }
  190.  
  191. let element = document.getElementsByClassName("guess-map_canvas__cvpqv")[0];
  192. if(!element){
  193. placeMarkerStreaks();
  194. return;
  195. }
  196. const keys = Object.keys(element);
  197. const key = keys.find(key => key.startsWith("__reactFiber$"));
  198. const props = element[key];
  199. const x = props.return.return.memoizedProps.map.__e3_.click;
  200. const y = Object.keys(x)[0];
  201. const z = {
  202. latLng:{
  203. lat: () => lat,
  204. lng: () => lng,
  205. }
  206. };
  207.  
  208. const xy = x[y];
  209. const a = Object.keys(x[y]);
  210.  
  211. for(let i = 0; i < a.length ;i++){
  212. let q = a[i];
  213. if (typeof xy[q] === "function"){
  214. xy[q](z);
  215. }
  216. }
  217. }
  218.  
  219. function placeMarkerStreaks(){
  220. let {lat,lng} = globalCoordinates;
  221. let element = document.getElementsByClassName("region-map_mapCanvas__R95Ki")[0];
  222. if(!element){
  223. return;
  224. }
  225. const keys = Object.keys(element);
  226. const key = keys.find(key => key.startsWith("__reactFiber$"));
  227. const props = element[key];
  228. const x = props.return.return.memoizedProps.map.__e3_.click;
  229. const y = Object.keys(x);
  230. const w = "(e.latLng.lat(),e.latLng.lng())}";
  231. const v = {
  232. latLng:{
  233. lat: () => lat,
  234. lng: () => lng,
  235. }
  236. };
  237. for(let i = 0; i < y.length; i++){
  238. const curr = Object.keys(x[y[i]]);
  239. let func = curr.find(l => typeof x[y[i]][l] === "function");
  240. let prop = x[y[i]][func];
  241. if(prop && prop.toString().slice(5) === w){
  242. prop(v);
  243. }
  244. }
  245. }
  246.  
  247. function mapsFromCoords() {
  248. const {lat, lng} = globalCoordinates;
  249. if (!lat || !lng) {
  250. return;
  251. }
  252.  
  253. const mapUrl = `https://maps.google.com/?output=embed&q=${lat},${lng}&ll=${lat},${lng}&z=5`;
  254. window.open(mapUrl, '_blank', 'width=600,height=600,resizable=yes,scrollbars=yes');
  255. }
  256.  
  257. // Add a black box on the right side of the screen
  258. function createBlackBox() {
  259. const blackBox = document.createElement('div');
  260. blackBox.id = 'blackBox'; // Adding an ID for easy reference
  261. blackBox.style.position = 'fixed';
  262. blackBox.style.top = '0'; // Set the top position to 0 for top of the page
  263. blackBox.style.left = '50%'; // Center horizontally
  264. blackBox.style.transform = 'translateX(-50%)'; // Center horizontally
  265. blackBox.style.width = '200px';
  266. blackBox.style.height = '2%';
  267. blackBox.style.backgroundColor = 'black';
  268. blackBox.style.color = 'white';
  269. blackBox.style.padding = '20px';
  270. blackBox.style.zIndex = '9999';
  271. blackBox.style.outline = '2px solid red'; // Add red outline
  272. blackBox.innerHTML = '<span style="font-size: 16px;">Press INSERT to view the guide</span>';
  273.  
  274. document.body.appendChild(blackBox);
  275.  
  276. // Schedule the removal of the black box after 5 seconds
  277. setTimeout(function() {
  278. const blackBoxToRemove = document.getElementById('blackBox');
  279. if (blackBoxToRemove) {
  280. blackBoxToRemove.style.opacity = '0';
  281. setTimeout(function() {
  282. blackBoxToRemove.remove();
  283. }, 1000); // Fade out transition time
  284. }
  285. }, 9000); // 5 seconds
  286. }
  287.  
  288. // Call the function to create the black box on page load
  289. createBlackBox();
  290.  
  291. let popupVisible = false;
  292.  
  293. function togglePopup() {
  294. const popup = document.getElementById('popup');
  295.  
  296. if (!popup) {
  297. // Create popup element
  298. const popupElement = document.createElement('div');
  299. popupElement.id = 'popup';
  300. popupElement.style.position = 'fixed';
  301. popupElement.style.top = '50%';
  302. popupElement.style.left = '50%';
  303. popupElement.style.transform = 'translate(-50%, -50%)';
  304. popupElement.style.backgroundColor = 'black';
  305. popupElement.style.color = 'white';
  306. popupElement.style.padding = '20px';
  307. popupElement.style.zIndex = '9999';
  308.  
  309. // Create an inner div for the text content
  310. const textDiv = document.createElement('div');
  311. textDiv.innerHTML = 'Press [1] to pick an close spot to the destination pin<br><br>Press [2] to place your pin on the exact location of the destination<br><br>Press [3] to open an separate window that opens google maps on the exact location<br><br>-----------------------------------------------------------------------------------------<br><br>Press [P] in classic maps / world when you are in the match to start farming';
  312. popupElement.appendChild(textDiv);
  313.  
  314. // Create an inner div for the rainbow border
  315. const borderDiv = document.createElement('div');
  316. borderDiv.classList.add('popup-border');
  317. popupElement.appendChild(borderDiv);
  318.  
  319. document.body.appendChild(popupElement);
  320. popupVisible = true;
  321. } else {
  322. popup.style.display = popupVisible ? 'none' : 'block';
  323. popupVisible = !popupVisible;
  324. }
  325.  
  326. // Dynamically adjust the rainbow border size
  327. const borderDiv = document.querySelector('.popup-border');
  328. if (borderDiv) {
  329. const popupContent = document.getElementById('popup');
  330. if (popupContent) {
  331. borderDiv.style.width = `${popupContent.offsetWidth}px`;
  332. borderDiv.style.height = `${popupContent.offsetHeight}px`;
  333. }
  334. }
  335. }
  336. function pathMatches(path) {
  337. return location.pathname.match(new RegExp(`^/(?:[^/]+/)?${path}$`))
  338. }
  339.  
  340. function getIndex(element) {
  341. if (!element) return -1
  342.  
  343. let i = 0
  344. while (element = element.previousElementSibling) {
  345. i++
  346. }
  347.  
  348. return i
  349. }
  350.  
  351. const OBSERVER_CONFIG = {
  352. characterDataOldValue: false,
  353. subtree: true,
  354. childList: true,
  355. characterData: false
  356. }
  357.  
  358.  
  359. /////////////////////////////////////////////////////////////////////
  360. /// BATTLEROYALE START ///
  361.  
  362.  
  363. // Function to check if the desired element is present before loading the main script
  364. const waitForElement = async () => {
  365. while (!document.getElementsByClassName("game-mode-brand_possibleTitle__xR3HP game-mode-brand_selected__TxTvh")[0]) { // LEAVE IT ON THIS ELEMENT FOR IT TO LOAD NORMALLY! AKA BATTLEROYALE LOGO IN WAITING LOBBY
  366. await new Promise(r => setTimeout(r, 1000));
  367. console.log("Waiting for lobby card...");
  368. }
  369. console.log("Lobby card found. Loading script...");
  370. // Execute the main function
  371. loadScript();
  372. };
  373.  
  374. // Start checking for the lobby card element
  375. waitForElement();
  376.  
  377. // Function to load the main script
  378. function loadScript() {
  379. // Main script code goes here
  380. (async function() {
  381. 'use strict';
  382.  
  383. // Define the API URL to retrieve country data (optional)
  384. const apiURL = "https://restcountries.com/v3.1/all?fields=name,flags";
  385.  
  386. console.log("Script started.");
  387.  
  388. // Wait until the UI element with class "countries-game-overview_overview__0cpdi" is loaded
  389. while (!document.querySelector(".countries-game-overview_overview__0cpdi")) {
  390. await new Promise(r => setTimeout(r, 1000));
  391. console.log("Waiting for UI to load...");
  392. }
  393. console.log("UI loaded.");
  394.  
  395. let flagsProcessed = false;
  396.  
  397. function showNames() {
  398. console.log("Retrieving all guessed flags...");
  399. // Retrieve all elements with class related to guessed flags
  400. let flags = document.querySelectorAll(".countries-game-overview_wrongGuessesFlag__U4XmC");
  401.  
  402. for (let flag of flags) {
  403. let flag_img = flag.querySelector("img");
  404. if (flag_img && flag_img.getAttribute("alt")) {
  405. let country_code = flag_img.getAttribute("alt").toUpperCase().substring(0, 2); // Get the first two characters of the country code
  406.  
  407. // Create the country code element
  408. let countryCodeElement = document.createElement("span");
  409. countryCodeElement.textContent = country_code;
  410. countryCodeElement.className = "country-code";
  411.  
  412. // Position the country code above the flag element
  413. let flagRect = flag.getBoundingClientRect();
  414. let bodyRect = document.body.getBoundingClientRect();
  415. countryCodeElement.style.position = "absolute";
  416. countryCodeElement.style.top = flagRect.top - bodyRect.top - 20 + "px"; // Adjust this value as needed (above the flag)
  417. countryCodeElement.style.left = flagRect.left - bodyRect.left + "px"; // Align with the left edge of the flag
  418. countryCodeElement.style.fontSize = "0.8rem"; // Adjust font size as needed
  419. countryCodeElement.style.zIndex = "9999"; // Ensure the country code appears above the flag
  420.  
  421. // Insert the country code element above the flag element
  422. document.body.appendChild(countryCodeElement); // Append to the body to position it above the flag element
  423. }
  424. }
  425.  
  426. flagsProcessed = true;
  427. console.log("All flags processed.");
  428. }
  429.  
  430. // Add CSS style to position the country code element above the flag image
  431. let style = document.createElement('style');
  432. style.textContent = `
  433. .country-flag_flag__tlHIr {
  434. position: relative;
  435. }
  436.  
  437. .country-code {
  438. position: absolute !important;
  439. top: -20px !important; /* Adjust this value as needed (above the flag) */
  440. left: 0; /* Align with the left edge of the flag image */
  441. font-size: 0.8rem; /* Adjust font size as needed */
  442. z-index: 9999; /* Ensure the country code appears above the flag image */
  443. }
  444. `;
  445. document.head.appendChild(style);
  446.  
  447. // **Fix 2: MutationObserver update (for new guesses)**
  448. var observer = new MutationObserver(function(mutations) {
  449. for (let mutation of mutations) {
  450. if (mutation.type === "childList" && mutation.target.className === "countries-game-overview_wrongGuessesFlags__GEhji") {
  451. console.log("New flag guessed. Updating...");
  452.  
  453. // Loop through added nodes to find new flag elements
  454. for (let addedNode of mutation.addedNodes) {
  455. if (addedNode.classList && addedNode.classList.contains("countries-game-overview_wrongGuessesFlag__U4XmC")) {
  456. // Extract country code and insert element for the new flag
  457. let flag_img = addedNode.querySelector("img");
  458. if (flag_img && flag_img.getAttribute("alt")) {
  459. let country_code = flag_img.getAttribute("alt").toUpperCase().substring(0, 2); // Get the first two characters of the country code
  460.  
  461. let countryCodeElement = document.createElement("span");
  462. countryCodeElement.textContent = country_code;
  463. countryCodeElement.className = "country-code";
  464. countryCodeElement.style.position = "absolute"; // Absolute positioning for precise placement
  465. countryCodeElement.style.top = "0.2rem"; // Adjust this value as needed (slightly above the flag)
  466. countryCodeElement.style.right = "0.2rem"; // Adjust this value as needed (slightly to the right)
  467. countryCodeElement.style.fontSize = "0.8rem"; // Adjust font size as needed
  468.  
  469. // Insert the country code element next to the flag image
  470. addedNode.insertBefore(countryCodeElement, addedNode.querySelector("img")); // Insert before the image
  471. }
  472. }
  473. }
  474. }
  475. }
  476. });
  477.  
  478. // Start observing the "countries-game-overview_wrongGuessesFlags__GEhji" element for child list changes
  479. observer.observe(document.querySelector(".countries-game-overview_wrongGuessesFlags__GEhji"), { attributes: false, childList: true, characterData: false, subtree: true });
  480.  
  481. // Call the function to process existing flags on startup
  482. showNames();
  483.  
  484. // Function to reset the script when the match ends
  485. function resetScript() {
  486. // Function to check for the end game screen class
  487. const checkEndGameScreen = async () => {
  488. while (true) {
  489. const endGameScreens = document.querySelectorAll(".popup-view_popupView__TJqKD, .spectate-footer_messageText__jHqwQ");
  490. let foundEndGameScreen = false;
  491.  
  492. endGameScreens.forEach(screen => {
  493. if (
  494. screen &&
  495. window.getComputedStyle(screen).display !== 'none' &&
  496. !screen.classList.contains('popup-view_isCorrect__oQmkS') && // Exclude correct modal
  497. !screen.classList.contains('popup-view_isItalic__1Fbl4') && // Exclude correct modal
  498. (screen.querySelector('[data-qa="popup-view-lost"]') || // Check for "You were knocked out" text
  499. screen.textContent.includes("You are knocked out.") || // Check for "You are knocked out" text in <p> element
  500. screen.getAttribute("data-qa") === "spectating-modal") // Check for "spectating-modal" data-qa attribute
  501. ) {
  502. foundEndGameScreen = true;
  503. }
  504. });
  505.  
  506. if (foundEndGameScreen) {
  507. // End game screen found, reload the script
  508. console.log("End game screen found. Resetting script...");
  509. observer.disconnect(); // Disconnect the existing observer
  510. waitForElement(); // Restart the script
  511. break; // Exit the loop once the end game screen is found
  512. } else {
  513. // End game screen not found, continue checking
  514. await new Promise(r => setTimeout(r, 1000));
  515. console.log("Looking for end game screen...");
  516. }
  517. }
  518. };
  519.  
  520. // Start checking for the end game screen class
  521. checkEndGameScreen();
  522. }
  523.  
  524. // Start observing for match end
  525. resetScript();
  526. })();
  527. };
  528. /////////////////////////////////////////////////////////////////////
  529. /// BATTLEROYALE END ///
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536. /////////////// DEPLOY EXTRA INFORMATION BOX ///////////////////
  537.  
  538. // Define coordinatesData object
  539. const coordinatesData = {
  540. lat: null,
  541. lng: null
  542. };
  543.  
  544. // Function to resolve the location, fetch country information, and apply overlay on the map
  545. async function resolveLocationAndApplyOverlayNew() {
  546. const { lat, lng } = coordinatesData;
  547. try {
  548. const countryInfo = lat && lng ? await fetchCountryInfoNew(lat, lng) : null;
  549. showCountryInfoNew(countryInfo); // Display the country info
  550. } catch (error) {
  551. console.error('Error fetching country information:', error);
  552. }
  553. }
  554.  
  555. // Function to display the country name, state, and city on the site with black outline around the letters
  556. function showCountryInfoNew(countryInfo) {
  557. let countryInfoElement = document.getElementById('geoguessr-country-info');
  558. if (!countryInfoElement) {
  559. countryInfoElement = document.createElement('div');
  560. countryInfoElement.id = 'geoguessr-country-info';
  561. countryInfoElement.classList.add('geoguessr-country-info');
  562. countryInfoElement.style.position = 'fixed';
  563. countryInfoElement.style.top = '70%';
  564. countryInfoElement.style.right = '10px';
  565. countryInfoElement.style.width = '200px'; // Fixed width
  566. countryInfoElement.style.height = 'auto'; // Auto height
  567. countryInfoElement.style.transform = 'translateY(-50%)';
  568. countryInfoElement.style.fontFamily = 'Arial, sans-serif'; // Set font family
  569. countryInfoElement.style.fontSize = '20px'; // Set font size
  570. countryInfoElement.style.color = 'transparent';
  571. countryInfoElement.style.webkitBackgroundClip = 'text';
  572. countryInfoElement.style.animation = 'rainbow 10s linear infinite';
  573. countryInfoElement.style.textShadow = '0 2 5px white'; // Add black outline around the letters
  574. countryInfoElement.style.padding = '10px';
  575. countryInfoElement.style.borderRadius = '10px';
  576. countryInfoElement.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.3)';
  577. countryInfoElement.style.background = 'rgba(0, 0, 0, 0.5)'; // Semi-transparent black background
  578. countryInfoElement.style.zIndex = '9999'; // Ensure it appears on top of other elements
  579. document.body.appendChild(countryInfoElement);
  580.  
  581. // Add minimize button
  582. const minimizeButton = document.createElement('span');
  583. minimizeButton.classList.add('geoguessr-minimize-button');
  584. minimizeButton.innerHTML = '&#10006;'; // Unicode for 'X'
  585. minimizeButton.style.position = 'absolute';
  586. minimizeButton.style.top = '5px';
  587. minimizeButton.style.right = '5px';
  588. minimizeButton.style.cursor = 'pointer';
  589. minimizeButton.style.color = 'white';
  590. minimizeButton.style.zIndex = '99999'; // Ensure it appears on top of other elements
  591. minimizeButton.addEventListener('click', toggleCountryInfoSize);
  592. countryInfoElement.appendChild(minimizeButton);
  593.  
  594. // Make the text draggable
  595. makeElementDraggableNew(countryInfoElement);
  596. }
  597.  
  598. // Set the text content with rainbow-colored text
  599. countryInfoElement.innerHTML = '';
  600. if (countryInfo) {
  601. countryInfoElement.innerHTML +=
  602. `<div style="animation: rainbow 10s linear infinite">Country: ${countryInfo.country || 'N/A'}</div>` +
  603. `<div style="animation: rainbow 10s linear infinite">State: ${countryInfo.state || 'N/A'}</div>` +
  604. `<div style="animation: rainbow 10s linear infinite">City: ${countryInfo.city || 'N/A'}</div>`;
  605. } else {
  606. countryInfoElement.innerHTML =
  607. `<div style="animation: rainbow 10s linear infinite">Country: N/A</div>` +
  608. `<div style="animation: rainbow 10s linear infinite">State: N/A</div>` +
  609. `<div style="animation: rainbow 10s linear infinite">City: N/A</div>`;
  610. }
  611. }
  612.  
  613. // Function to make an element draggable
  614. function makeElementDraggableNew(element) {
  615. let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  616. element.onmousedown = dragMouseDownNew;
  617.  
  618. function dragMouseDownNew(e) {
  619. e = e || window.event;
  620. e.preventDefault();
  621. pos3 = e.clientX;
  622. pos4 = e.clientY;
  623. document.onmouseup = closeDragElementNew;
  624. document.onmousemove = elementDragNew;
  625. }
  626.  
  627. function elementDragNew(e) {
  628. e = e || window.event;
  629. e.preventDefault();
  630. pos1 = pos3 - e.clientX;
  631. pos2 = pos4 - e.clientY;
  632. pos3 = e.clientX;
  633. pos4 = e.clientY;
  634. element.style.top = (element.offsetTop - pos2) + "px";
  635. element.style.left = (element.offsetLeft - pos1) + "px";
  636. }
  637.  
  638. function closeDragElementNew() {
  639. document.onmouseup = null;
  640. document.onmousemove = null;
  641. }
  642. }
  643.  
  644. // Function to toggle visibility of country info box
  645. function toggleCountryInfoSize() {
  646. const countryInfoElement = document.getElementById('geoguessr-country-info');
  647. countryInfoElement.classList.toggle('geoguessr-country-info-small');
  648. }
  649.  
  650. // Function to reset coordinatesData
  651. function resetCoordinatesData() {
  652. coordinatesData.lat = null;
  653. coordinatesData.lng = null;
  654. }
  655.  
  656. // Function to update country info
  657. async function updateCountryInfo() {
  658. const { lat, lng } = coordinatesData;
  659. try {
  660. let countryInfo;
  661. if (lat !== null && lng !== null) {
  662. countryInfo = await fetchCountryInfoNew(lat, lng);
  663. } else {
  664. countryInfo = null; // Set countryInfo to null when coordinates are not available
  665. resetCoordinatesData(); // Reset coordinatesData when no coordinates are available
  666. }
  667. showCountryInfoNew(countryInfo);
  668. } catch (error) {
  669. console.error('Error fetching country information:', error);
  670. }
  671. }
  672.  
  673. // Start actively checking for coordinates changes
  674. async function checkForCoordinatesChanges() {
  675. while (true) {
  676. const { lat, lng } = coordinatesData;
  677. try {
  678. if (lat !== null && lng !== null) {
  679. await updateCountryInfo();
  680. }
  681. } catch (error) {
  682. console.error('Error checking for coordinates changes:', error);
  683. }
  684. await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second before checking again
  685. }
  686. }
  687.  
  688. // Start checking for coordinates changes
  689. checkForCoordinatesChanges();
  690.  
  691. // Intercept the API call to retrieve coordinates
  692. var originalOpen1 = XMLHttpRequest.prototype.open;
  693. XMLHttpRequest.prototype.open = function (method, url) {
  694. if (url.startsWith('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata')) {
  695. this.addEventListener('load', async function () {
  696. let interceptedResult = this.responseText;
  697. const pattern = /-?\d+\.\d+,-?\d+\.\d+/g;
  698. let match = interceptedResult.match(pattern)[0];
  699. let split = match.split(",");
  700. let lat = Number.parseFloat(split[0]);
  701. let lng = Number.parseFloat(split[1]);
  702. coordinatesData.lat = lat;
  703. coordinatesData.lng = lng;
  704. });
  705. }
  706. return originalOpen1.apply(this, arguments);
  707. };
  708.  
  709. // Function to fetch country information based on coordinates using Nominatim reverse geocoding API
  710. async function fetchCountryInfoNew(lat, lng) {
  711. try {
  712. const response = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`);
  713. if (!response.ok) {
  714. throw new Error(`Failed to fetch country information: ${response.status} ${response.statusText}`);
  715. }
  716. const data = await response.json();
  717. if (data && data.address) {
  718. const country = data.address.country || 'Unknown';
  719. const state = data.address.state || 'Unknown';
  720. const city = data.address.city || data.address.town || 'Unknown';
  721. return { country, state, city };
  722. } else {
  723. throw new Error('No country information found');
  724. }
  725. } catch (error) {
  726. console.error('Error fetching country information:', error);
  727. throw error; // Propagate the error further
  728. }
  729. }
  730.  
  731. // Add CSS styling
  732. const styling = document.createElement('style');
  733. styling.textContent = `
  734. .geoguessr-country-info {
  735. display: block;
  736. }
  737.  
  738. .geoguessr-country-info-small {
  739. width: auto;
  740. height: 30px;
  741. }
  742.  
  743. #geoguessr-country-info {
  744. position: fixed;
  745. top: 70%;
  746. right: 10px;
  747. transform: translateY(-50%);
  748. font-family: Arial, sans-serif;
  749. font-size: 20px;
  750. color: transparent;
  751. background: -webkit-linear-gradient(45deg, #e6e6fa, #add8e6, #87cefa, #00ff00, #ffff00, #ffa500, #ff6347);
  752. -webkit-background-clip: text;
  753. animation: rainbow 10s linear infinite;
  754. text-shadow: 0 0 5px rgba(255, 255, 255, 0.5); /* Light white shadow */
  755. -webkit-text-stroke: 1px rgba(255, 255, 255, 0.5); /* Light white outline */
  756. padding: 10px;
  757. border-radius: 10px;
  758. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
  759. background: rgba(0, 0, 0, 0.5);
  760. border: 2px solid transparent; /* Set initial transparent border */
  761. border-image: linear-gradient(to right, rgba(255,0,0,0), rgba(255,0,0,0.5), rgba(255,0,0,0)) 30; /* Smooth gradient border */
  762. border-image-slice: 1;
  763. }
  764. `;
  765. document.head.appendChild(styling);
  766.  
  767. // Initially display country info
  768. resolveLocationAndApplyOverlayNew();
  769.  
  770. /////////////// EBD ///////////////////
  771.  
  772.  
  773.  
  774.  
  775.  
  776. // Define CSS animation for rainbow border around black box when pressing insert
  777. const styles = `
  778. @keyframes rainbow-border {
  779. 0% { border-color: red; }
  780. 16.666% { border-color: orange; }
  781. 33.333% { border-color: yellow; }
  782. 50% { border-color: green; }
  783. 66.666% { border-color: blue; }
  784. 83.333% { border-color: indigo; }
  785. 100% { border-color: violet; }
  786. }
  787.  
  788.  
  789.  
  790. @keyframes moveHeader {
  791. 0% {
  792. transform: translateX(-1px) translateY(-1px);
  793. }
  794. 50% {
  795. transform: translateX(1px) translateY(1px);
  796. }
  797. 100% {
  798. transform: translateX(-1px) translateY(-1px);
  799. }
  800. }
  801.  
  802. .header_pageLabel__IIJf8 {
  803. animation: moveHeader 5s infinite alternate;
  804. }
  805.  
  806. .custom-menu-position {
  807. justify-content: flex-end; /* Aligns items to the right */
  808. /* Add more custom positioning styles as needed */
  809. }
  810.  
  811.  
  812.  
  813. .header_header__JSEeB {
  814. /* Add CSS properties to position the header to the right */
  815. display: flex;
  816. justify-content: flex-end; /* Aligns header to the right */
  817. /* Add more custom styling as needed */
  818. }
  819.  
  820. .header_pageLabel__IIJf8 {
  821. /* Add CSS properties to ensure the menu stays on the right */
  822. /* You may need to adjust other properties such as margin or padding */
  823. /* Add more custom styling as needed */
  824. }
  825. .popup-border {
  826. position: absolute;
  827. top: 0;
  828. left: 50%; /* Adjust left position as needed */
  829. transform: translateX(-50%); /* Center the border horizontally */
  830. border: 5px solid transparent;
  831. box-sizing: border-box; /* Include padding in width and height */
  832. animation: rainbow-border 5s infinite;
  833. pointer-events: none; /* Make sure the border doesn't interfere with mouse events */
  834. }
  835.  
  836. /* Tooltip container */
  837. .tooltip {
  838. position: relative;
  839. display: inline-block;
  840. border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
  841. }
  842.  
  843.  
  844. .primary-menu_wrapper__3ahEU {
  845. position: absolute;
  846. left: calc(40% - 180px);
  847. top: 30%;
  848. transform: translate(-50%, -50%);
  849. width: 360px;
  850. height: 530px;
  851. background-color: black;
  852. border: 2px solid limegreen; /* Change border color to lime green */
  853. border-radius: 10px;
  854. z-index: 9999;
  855.  
  856. /* Add animation properties */
  857. animation: pulse1 2s infinite; /* Use pulse1 as the animation name */
  858. animation-name: pulse1; /* Specify the animation name */
  859. }
  860.  
  861. @keyframes pulse1 {
  862. 0% {
  863. border-color: limegreen; /* Start with lime green */
  864. }
  865. 50% {
  866. border-color: red; /* Change to red halfway through */
  867. }
  868. 100% {
  869. border-color: limegreen; /* Return to lime green */
  870. }
  871. }
  872.  
  873. .game-menu-button_button__qIY8u:hover {
  874. animation: color-sweep 5s infinite;
  875. }
  876.  
  877. @keyframes color-sweep {
  878. 0% { color: rgb(255, 0, 0); }
  879. 25% { color: rgb(0, 255, 0); }
  880. 50% { color: rgb(0, 0, 255); }
  881. 75% { color: rgb(255, 255, 0); }
  882. 100% { color: rgb(255, 0, 255); }
  883. }
  884.  
  885.  
  886.  
  887. /* Tooltip text */
  888. .tooltip .tooltiptext {
  889. visibility: hidden;
  890. width: 120px;
  891. background-color: #555;
  892. color: #fff;
  893. text-align: center;
  894. border-radius: 6px;
  895. padding: 5px 0;
  896. position: absolute;
  897. z-index: 1;
  898. bottom: 125%;
  899. left: 50%;
  900. margin-left: -60px;
  901. opacity: 0;
  902. transition: opacity 0.3s;
  903. }
  904.  
  905. /* Tooltip text shown on hover */
  906. .tooltip:hover .tooltiptext {
  907. visibility: visible;
  908. opacity: 1;
  909. }
  910.  
  911. /* Custom styling for the signed-in-start-page_menu__2CH3S */
  912. signed-in-start-page_menu__2CH3S {
  913. width: 130%; /* Adjust this value to change the length of the divider */
  914. left: 133%; /* Adjust this value to move the divider more to the right */
  915. }
  916.  
  917.  
  918. /* Custom styling for the footer_footer__tc8Gv */
  919. .footer_footer__tc8Gv {
  920. margin-bottom: 20px; /* Adjust this value to move the footer up or down */
  921. }
  922.  
  923.  
  924. .primary-menu-button_flairContainer__YaBOt {
  925. margin-left: 223px; /* Adjust this value to move the button further to the right */
  926. }
  927.  
  928.  
  929. /* GIF background for the site */
  930. body {
  931. background-image: url('https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/b7f09246-ac57-40d3-97ac-4ed7562a8152/df3i4lx-0132abba-7479-4bd3-939c-9fca9c792cbc.gif?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2I3ZjA5MjQ2LWFjNTctNDBkMy05N2FjLTRlZDc1NjJhODE1MlwvZGYzaTRseC0wMTMyYWJiYS03NDc5LTRiZDMtOTM5Yy05ZmNhOWM3OTJjYmMuZ2lmIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.J8DhZACK1XXgqaCSc4UvdjtXkq4RFL0PsfOQwsjp7bM');
  932. background-size: cover;
  933. background-repeat: repeat;
  934. }
  935.  
  936. .tooltip {
  937. position: absolute;
  938. background-color: #fff;
  939. border: 1px solid #ccc;
  940. padding: 5px;
  941. border-radius: 5px;
  942. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
  943. }
  944.  
  945. /* Define CSS animation for rainbow background */
  946. @keyframes rainbow-background {
  947. 0% { background-color: red; }
  948. 12.5% { background-color: orange; }
  949. 25% { background-color: yellow; }
  950. 37.5% { background-color: green; }
  951. 50% { background-color: blue; }
  952. 62.5% { background-color: indigo; }
  953. 75% { background-color: violet; }
  954. 87.5% { background-color: red; }
  955. 100% { background-color: orange; }
  956. }
  957.  
  958. /* RGB border around the site */
  959. html {
  960. border-top: 20px solid transparent;
  961. border-bottom: -30px solid transparent; /* Adjust bottom border width */
  962. border-left: 20px solid transparent; /* Adjust left border width */
  963. border-right: 20px solid transparent; /* Adjust right border width */
  964. animation: rainbow-background 8s infinite linear; /* Adjust the animation duration and timing function */
  965. }
  966. `;
  967.  
  968. const element = document.getElementById('toggleScript');
  969.  
  970. if (element) {
  971. // Element exists, access its textContent property
  972. const textContent = element.textContent;
  973. // Do something with textContent
  974. } else {
  975. // Element does not exist, handle the error gracefully
  976. console.error('Element not found.');
  977. }
  978.  
  979.  
  980. // ON THE SITE ELEMENTS TO MAKE IT LOOK DIFFERENT
  981.  
  982. function removeLogoElements() {
  983. const logoElements = document.querySelectorAll('img.header_logoImage__eYuyg');
  984. logoElements.forEach(element => {
  985. element.remove();
  986. });
  987. }
  988.  
  989. // Function to remove specified elements
  990. function removeElements() {
  991. const elementsToRemove = document.querySelectorAll('.signed-in-start-page_socialAndLegalLinks__kcYwR');
  992. elementsToRemove.forEach(element => {
  993. element.remove();
  994. });
  995. }
  996.  
  997. // Function to remove specified elements
  998. function removeElements2() {
  999. const elementsToRemove = document.querySelectorAll('.signed-in-start-page_socialAndLegalLinks__kcYwR, .startpage_avatarWrapper__j4Iua');
  1000. elementsToRemove.forEach(element => {
  1001. element.remove();
  1002. });
  1003. }
  1004.  
  1005. // Function to remove specified elements
  1006. function removeElements3() {
  1007. const elementsToRemove = document.querySelectorAll('.signed-in-start-page_gradientPlate__A_ziw');
  1008. elementsToRemove.forEach(element => {
  1009. element.remove();
  1010. });
  1011. }
  1012.  
  1013. // Function to remove specified elements
  1014. function removeElements5() {
  1015. const elementsToRemove = document.querySelectorAll('.game_inGameLogos__aDZlA');
  1016. elementsToRemove.forEach(element => {
  1017. element.remove();
  1018. });
  1019. }
  1020.  
  1021. // Function to remove specified elements
  1022. function removeElementsWithHrefAndClass() {
  1023. const elementsToRemove = document.querySelectorAll('[href="/me/likes"].profile_profileLink__NOzps');
  1024. elementsToRemove.forEach(element => {
  1025. element.removeAttribute('href');
  1026. element.classList.remove('profile_profileLink__NOzps');
  1027. });
  1028. }
  1029.  
  1030. // Remove elements every 2 milliseconds
  1031. setInterval(removeElementsWithHrefAndClass, 2);
  1032.  
  1033.  
  1034. // Remove specified elements initially
  1035. setInterval(removeElements2, 10);
  1036. setInterval(removeElements3, 10);
  1037. setInterval(removeElements5, 10);
  1038.  
  1039. // Check for specified elements every 10,000 seconds and remove them if found
  1040. setInterval(removeElements, 10); // 10,000 seconds
  1041.  
  1042. // Remove specified elements initially
  1043. removeElements();
  1044.  
  1045. // Check for specified elements every 10,000 seconds and remove them if found
  1046. setInterval(removeElements, 10); // 10,000 seconds
  1047.  
  1048. // Check for logo elements every second and remove them if found
  1049. setInterval(removeLogoElements, 10);
  1050.  
  1051.  
  1052. // Create style element and append to document head
  1053. const styleElement = document.createElement('style');
  1054. styleElement.textContent = styles;
  1055. document.head.appendChild(styleElement);
  1056.  
  1057. // Function to check and fade out the specified div if its opacity is back to 1
  1058. function checkAndFadeOut() {
  1059. const backgroundDiv1 = document.querySelector('.background_background__8Zm0Y.background_backgroundHome__lurxW');
  1060. const backgroundDiv2 = document.querySelector('.background_background__8Zm0Y.background_backgroundRankedSystem__wk1Dw');
  1061. const backgroundDiv3 = document.querySelector('.background_background__8Zm0Y.background_backgroundProfile__EY4oP');
  1062.  
  1063. if (backgroundDiv1 && backgroundDiv1.style.opacity === '1') {
  1064. backgroundDiv1.style.transition = 'opacity 1s';
  1065. backgroundDiv1.style.opacity = '0';
  1066. }
  1067.  
  1068. if (backgroundDiv2 && backgroundDiv2.style.opacity === '1') {
  1069. backgroundDiv2.style.transition = 'opacity 1s';
  1070. backgroundDiv2.style.opacity = '0';
  1071. }
  1072. if (backgroundDiv3 && backgroundDiv3.style.opacity === '1') {
  1073. backgroundDiv3.style.transition = 'opacity 1s';
  1074. backgroundDiv3.style.opacity = '0';
  1075. }
  1076. }
  1077.  
  1078. // Set the opacity of the specified classes to 0 after 2 seconds when the page has loaded
  1079. window.addEventListener('load', function() {
  1080. setTimeout(function() {
  1081. checkAndFadeOut(); // Check and fade out initially after 2 seconds
  1082. setInterval(checkAndFadeOut, 1000); // Check every 1 second
  1083. }, 2000); // 2 seconds delay
  1084. });
  1085.  
  1086.  
  1087. function togglePopupBox() {
  1088. console.log('Toggling popup box...');
  1089. const popupBox = document.getElementById('popupBox');
  1090. if (popupBox) {
  1091. popupBox.style.display = popupBox.style.display === 'none' ? 'block' : 'none';
  1092. if (popupBox.style.display === 'block') {
  1093. // Schedule the removal of the popup box after 4 seconds
  1094. setTimeout(() => {
  1095. popupBox.style.opacity = '0';
  1096. setTimeout(() => {
  1097. popupBox.remove();
  1098. }, 1000); // Fade out transition time
  1099. }, 4000); // 4 seconds delay before fading out
  1100. }
  1101. } else {
  1102. // Create the popup box if it doesn't exist
  1103. const hintMessage = document.createElement('div');
  1104. hintMessage.id = 'popupBox';
  1105. hintMessage.className = 'popup';
  1106. hintMessage.textContent = xpFarmingEnabled ? 'Enabling XP farm, please wait...' : 'Disabling XP farm, please wait...';
  1107. document.body.appendChild(hintMessage);
  1108. // Schedule the removal of the popup box after 4 seconds
  1109. setTimeout(() => {
  1110. hintMessage.style.opacity = '0';
  1111. setTimeout(() => {
  1112. hintMessage.remove();
  1113. }, 1000); // Fade out transition time
  1114. }, 4000); // 4 seconds delay before fading out
  1115. }
  1116. }
  1117.  
  1118. // Define a global variable to keep track of XP farming status
  1119. let xpFarmingEnabled = false;
  1120.  
  1121. // Function to create and display the rainbow text
  1122. function showXPFarmStatus() {
  1123. // Check if the rainbow text element already exists
  1124. let rainbowText = document.getElementById('rainbowText');
  1125.  
  1126. // If it doesn't exist, create it
  1127. if (!rainbowText) {
  1128. rainbowText = document.createElement('div');
  1129. rainbowText.id = 'rainbowText';
  1130. rainbowText.style.position = 'fixed';
  1131. rainbowText.style.top = '20px'; // Adjust the top position as needed
  1132. rainbowText.style.right = '1400px'; // Adjust the right position as needed
  1133. rainbowText.style.fontSize = '16px';
  1134. rainbowText.style.fontWeight = 'bold';
  1135. rainbowText.style.animation = 'rainbow-text 2s linear infinite'; // Add rainbow animation
  1136.  
  1137. document.body.appendChild(rainbowText);
  1138. }
  1139.  
  1140. // Update the text content based on XP farming status
  1141. rainbowText.textContent = xpFarmingEnabled ? 'XP FARM: ENABLED' : 'XP FARM: DISABLED';
  1142. }
  1143.  
  1144. // Add CSS animation for rainbow text to the existing styleElement
  1145. styleElement.textContent += `
  1146. @keyframes rainbow-text {
  1147. 0% { color: red; }
  1148. 16.666% { color: orange; }
  1149. 33.333% { color: yellow; }
  1150. 50% { color: green; }
  1151. 66.666% { color: blue; }
  1152. 83.333% { color: indigo; }
  1153. 100% { color: violet; }
  1154. }
  1155. `;
  1156.  
  1157. async function toggleScript() {
  1158. console.log('Toggling script...');
  1159. xpFarmingEnabled = !xpFarmingEnabled; // Toggle XP farming status
  1160. console.log('XP farming enabled:', xpFarmingEnabled);
  1161. showXPFarmStatus(); // Update the rainbow text to reflect the new status
  1162.  
  1163. if (xpFarmingEnabled) {
  1164. togglePopupBox(); // Display the popup box when enabling XP farm
  1165. } else {
  1166. togglePopupBox(); // Display the popup box when disabling XP farm
  1167. }
  1168.  
  1169. isRunning = !isRunning;
  1170. if (isRunning) {
  1171. runScript();
  1172. } else {
  1173. isPaused = false; // Reset pause status when stopping the script
  1174. }
  1175. }
  1176.  
  1177. // Function to handle keydown events
  1178. function onKeyDown(e) {
  1179. if (e.keyCode === 45) {
  1180. togglePopup();
  1181. }
  1182. if (e.keyCode === 49) { // This is for placing a marker around the guessed location
  1183. e.stopImmediatePropagation();
  1184. placeMarker(true);
  1185. }
  1186. if (e.keyCode === 50) { // This is for precisely placing the marker on the guessed location
  1187. e.stopImmediatePropagation();
  1188. placeMarker(false);
  1189. }
  1190. if (e.keyCode === 51) { // This is for opening a separate window with Google Maps pinpointing the guessed location
  1191. e.stopImmediatePropagation();
  1192. mapsFromCoords(false);
  1193. }
  1194. if (e.keyCode === 52) { // This is for placing a marker further than the guessed location
  1195. e.stopImmediatePropagation();
  1196. }
  1197. if (e.key === 'p' || e.key === 'P') { // Check if the key pressed is the 'P' key
  1198. toggleScript(); // Call function to toggle XP farming status and start or stop the script
  1199. }
  1200. }
  1201.  
  1202. // Add event listener for keydown events
  1203. document.addEventListener("keydown", onKeyDown);
  1204.  
  1205. // Call the function to show XP farming status when the script runs
  1206. showXPFarmStatus();
  1207.  
  1208.  
  1209. const popupStyles = `
  1210. .popup {
  1211. position: fixed;
  1212. top: 50%;
  1213. left: 50%;
  1214. transform: translate(-50%, -50%);
  1215. background-color: rgba(0, 0, 0, 0.8);
  1216. color: white;
  1217. padding: 20px;
  1218. border-radius: 10px;
  1219. z-index: 9999;
  1220. }
  1221.  
  1222. .popup p {
  1223. margin: 0;
  1224. }
  1225. `;
  1226.  
  1227. // Append popup styles to existing styleElement
  1228. styleElement.textContent += popupStyles;
  1229.  
  1230.  
  1231. // Custom button styles
  1232. const buttonStyles = `
  1233.  
  1234.  
  1235.  
  1236. .custom-button {
  1237. position: fixed;
  1238. bottom: 20px;
  1239. right: 100px; /* Adjust this value to move the button more to the left */
  1240. padding: 10px 20px;
  1241. font-size: 16px;
  1242. font-weight: bold;
  1243. text-transform: uppercase;
  1244. color: #fff;
  1245. background-color: #4CAF50;
  1246. border: none;
  1247. border-radius: 5px;
  1248. cursor: pointer;
  1249. transition: background-color 0.3s;
  1250. z-index: 9999;
  1251. animation: shake 0.5s infinite alternate; /* Shake animation */
  1252. }
  1253.  
  1254. .custom-button:hover {
  1255. background-color: #45a049;
  1256. }
  1257.  
  1258. /* Shake animation */
  1259. @keyframes shake {
  1260. 0% { transform: translateX(0); }
  1261. 100% { transform: translateX(-5px); } /* Adjust the distance and direction of the shake */
  1262. }
  1263.  
  1264. /* Spark animation */
  1265. @keyframes spark {
  1266. 0% { opacity: 0; }
  1267. 100% { opacity: 1; }
  1268. }
  1269.  
  1270. .sparks {
  1271. position: absolute;
  1272. width: 5px;
  1273. height: 5px;
  1274. background-color: #FFD700; /* Yellow color */
  1275. border-radius: 50%;
  1276. animation: spark 1s infinite alternate; /* Spark animation */
  1277. }
  1278.  
  1279. .spark1 {
  1280. top: -10px;
  1281. left: 0;
  1282. }
  1283.  
  1284. .spark2 {
  1285. top: -5px;
  1286. left: 15px;
  1287. }
  1288.  
  1289. .spark3 {
  1290. top: 15px;
  1291. left: 5px;
  1292. }
  1293.  
  1294. .hide {
  1295. display: none;
  1296. }
  1297. `;
  1298.  
  1299.  
  1300.  
  1301. // Remove the element on page reload
  1302. window.addEventListener('beforeunload', function() {
  1303. document.querySelector('.signed-in-start-page_avatar__eLI_o').remove();
  1304. });
  1305.  
  1306. // Set an interval to sweep-check for the element and remove it if found
  1307. setInterval(function() {
  1308. var element = document.querySelector('.signed-in-start-page_avatar__eLI_o');
  1309. if (element) {
  1310. element.remove();
  1311. }
  1312. }, 1); // Check every 1 second
  1313.  
  1314.  
  1315.  
  1316.  
  1317. // Append button styles to existing styleElement
  1318. styleElement.textContent += buttonStyles;
  1319.  
  1320.  
  1321. // Function to create and append the custom button
  1322. function createCustomButton() {
  1323. const button = document.createElement('button');
  1324. button.className = 'custom-button';
  1325. button.textContent = 'Join Discord';
  1326. button.onclick = function() {
  1327. window.open('https://discord.gg/5MXgjsN8vz', '_blank');
  1328. };
  1329. document.body.appendChild(button);
  1330. }
  1331.  
  1332. // Function to create and append the sparks
  1333. function createSparks() {
  1334. const spark = document.createElement('div');
  1335. spark.className = 'spark';
  1336. document.body.appendChild(spark);
  1337. setTimeout(() => {
  1338. spark.remove();
  1339. }, 1000);
  1340. }
  1341.  
  1342. // Function to display tooltips
  1343. function displayTooltip() {
  1344. const tooltips = [
  1345. "Join our server to stay updated!",
  1346. "press p in classic maps to farm xp!",
  1347. "Click me!!!",
  1348. // Add more tips as needed
  1349. ];
  1350. const randomIndex = Math.floor(Math.random() * tooltips.length);
  1351.  
  1352. const tooltip = document.createElement('div');
  1353. tooltip.className = 'tooltip';
  1354. tooltip.textContent = tooltips[randomIndex];
  1355. document.body.appendChild(tooltip);
  1356.  
  1357. const buttonRect = document.querySelector('.custom-button').getBoundingClientRect();
  1358. tooltip.style.top = buttonRect.top - tooltip.offsetHeight - 10 + 'px';
  1359.  
  1360. // Calculate the horizontal position based on the current position of the button
  1361. let leftPosition = buttonRect.left - tooltip.offsetWidth;
  1362. let animationId;
  1363.  
  1364. // Animate the tooltip to move with the button
  1365. function animateTooltip() {
  1366. leftPosition += 1; // Adjust the speed as needed
  1367. tooltip.style.left = leftPosition + 'px';
  1368. animationId = requestAnimationFrame(animateTooltip);
  1369. }
  1370.  
  1371. animateTooltip();
  1372.  
  1373. // Remove tooltip after some time
  1374. setTimeout(() => {
  1375. cancelAnimationFrame(animationId);
  1376. tooltip.remove();
  1377. }, 8000); // 8 seconds
  1378. }
  1379.  
  1380. // Main function to initialize the button and animations
  1381. function init() {
  1382. createCustomButton();
  1383. setInterval(createSparks, 2000); // Adjust timing for sparks
  1384. setInterval(displayTooltip, 50000); // Display tooltip every 5 minutes (300000 milliseconds)
  1385. }
  1386.  
  1387. // Initialize the script
  1388. init();
  1389.  
  1390.  
  1391. async function fetchWithCors(url, method, body) {
  1392. return await fetch(url, {
  1393. "headers": {
  1394. "accept": "*/*",
  1395. "accept-language": "en-US,en;q=0.8",
  1396. "content-type": "application/json",
  1397. "sec-fetch-dest": "empty",
  1398. "sec-fetch-mode": "cors",
  1399. "sec-fetch-site": "same-site",
  1400. "sec-gpc": "1",
  1401. "x-client": "web"
  1402. },
  1403. "referrer": "https://www.geoguessr.com/",
  1404. "referrerPolicy": "strict-origin-when-cross-origin",
  1405. "body": (method == "GET") ? null : JSON.stringify(body),
  1406. "method": method,
  1407. "mode": "cors",
  1408. "credentials": "include"
  1409. });
  1410. };
  1411.  
  1412. let friend_reqs_api = "https://www.geoguessr.com/api/v3/social/friends/summary?page=0&fast=true";
  1413. let delete_friend_req_api = (id) => `https://www.geoguessr.com/api/v3/social/friends/${id}`;
  1414.  
  1415. async function denyPlayer(id) {
  1416. await fetchWithCors(delete_friend_req_api(id), "DELETE", {});
  1417. console.log(`${id} denied`);
  1418. };
  1419.  
  1420. async function acceptPlayer(id) {
  1421. await fetchWithCors(delete_friend_req_api(id), "PUT", {});
  1422. console.log(`${id} accepted`);
  1423. };
  1424.  
  1425. function doit(accept) {
  1426. fetchWithCors(friend_reqs_api, "GET")
  1427. .then(ans => ans.json())
  1428. .then(json => {
  1429. for (let item of json.requests) {
  1430. accept ? acceptPlayer(item.userId) : denyPlayer(item.userId);
  1431. }
  1432. });
  1433. };
  1434.  
  1435. document.acceptAll = () => doit(true);
  1436. document.denyAll = () => doit(false);
  1437. document.doit = doit;
  1438.  
  1439. function makeButtons() {
  1440. const button = document.createElement("li");
  1441. button.classList.add("notification-list_notification__i0DH2");
  1442. button.style = "display: flex; justify-content: center; padding: 0 0; padding-bottom: 15px;";
  1443. button.innerHTML = `
  1444. <div class="notification-list_notificationActions__9JEe6" style="margin: auto;">
  1445. <button type="button" class="button_button__aR6_e button_variantPrimary__u3WzI" onclick="doit(true)" id="friend-reqs-true">
  1446. <div class="button_wrapper__NkcHZ">
  1447. <span>Accept everyone</span>
  1448. </div>
  1449. </button>
  1450. <button type="button" class="button_button__aR6_e button_variantPrimary__u3WzI" onclick="doit(false)" id="friend-reqs-false">
  1451. <div class="button_wrapper__NkcHZ">
  1452. <span>Deny everyone</span>
  1453. </div>
  1454. </button>
  1455. </div>`;
  1456. return button;
  1457. }
  1458.  
  1459. new MutationObserver(async (mutations) => {
  1460. if (document.getElementById("friend-reqs-true") != null) return;
  1461. const notifications = document.querySelector('ul[class*="notification-list_notifications__"]') || document.querySelector('div[class*="notification-list_noNotifications__"]');
  1462. if (notifications != null) {
  1463. const buttons = makeButtons();
  1464. notifications.insertBefore(buttons, notifications.childNodes[0]);
  1465. }
  1466. }).observe(document.body, { subtree: true, childList: true });
  1467.  
  1468. // Call the function to create and append the custom button
  1469. createCustomButton();
  1470.  
  1471. // Function to simulate a Space bar key press
  1472. function simulateSpaceKeyPress() {
  1473. // Create a new keyboard event for keydown event
  1474. const keyDownEvent = new KeyboardEvent('keydown', {
  1475. code: 'Space',
  1476. key: ' ',
  1477. keyCode: 32,
  1478. which: 32,
  1479. bubbles: true
  1480. });
  1481.  
  1482. // Dispatch the keydown event
  1483. document.dispatchEvent(keyDownEvent);
  1484.  
  1485. // Create a new keyboard event for keyup event
  1486. const keyUpEvent = new KeyboardEvent('keyup', {
  1487. code: 'Space',
  1488. key: ' ',
  1489. keyCode: 32,
  1490. which: 32,
  1491. bubbles: true
  1492. });
  1493.  
  1494. // Dispatch the keyup event after 1 second
  1495. setTimeout(() => {
  1496. document.dispatchEvent(keyUpEvent);
  1497. }, 5000); // Adjust the delay to 1000 milliseconds (1 second)
  1498. }
  1499.  
  1500. // Function to simulate key presses
  1501. async function simulateKeyPress(keyCode) {
  1502. const eventDown = new KeyboardEvent('keydown', { keyCode: keyCode });
  1503. const eventUp = new KeyboardEvent('keyup', { keyCode: keyCode });
  1504.  
  1505. document.dispatchEvent(eventDown);
  1506.  
  1507. // Dispatch the keyup event after 1 second
  1508. setTimeout(() => {
  1509. document.dispatchEvent(eventUp);
  1510. }, 5000); // Adjust the delay to 100 milliseconds
  1511. }
  1512.  
  1513.  
  1514. // Define global variables
  1515. let isRunning = false;
  1516. let isPaused = false;
  1517.  
  1518. async function toggleScript2() {
  1519. xpFarmingEnabled = !xpFarmingEnabled; // Toggle XP farming status
  1520. showXPFarmStatus(); // Update the rainbow text to reflect the new status
  1521.  
  1522. if (!xpFarmingEnabled) {
  1523. togglePopupBox(); // Hide the popup box when disabling XP farm
  1524. }
  1525.  
  1526. isRunning = !isRunning;
  1527. if (isRunning) {
  1528. runScript();
  1529. } else {
  1530. isPaused = false; // Reset pause status when stopping the script
  1531. }
  1532. }
  1533.  
  1534. // Function to start or pause the script
  1535. async function runScript() {
  1536. while (isRunning) {
  1537. if (!isPaused) {
  1538. await simulateKeyPress(50); // Press '2' key
  1539. await simulateSpaceKeyPress(); // Simulate Space bar key press
  1540.  
  1541. // Simulate clicking on the game canvas
  1542. const canvas = document.querySelector('.guess-map_canvas__cvpqv');
  1543. if (canvas) {
  1544. canvas.click();
  1545. }
  1546.  
  1547. // Delay for a short time
  1548. await new Promise(resolve => setTimeout(resolve, 500));
  1549. } else {
  1550. // Delay for a short time
  1551. await new Promise(resolve => setTimeout(resolve, 1007));
  1552. }
  1553. }
  1554. }
  1555.  
  1556.  
  1557. // Function to add the overlay with the waving hand emoji and text only on the main page
  1558. function addWelcomeOverlay() {
  1559. // Check if the current URL is the main page of GeoGuessr
  1560. if (window.location.pathname === '/') {
  1561. const overlay = document.createElement('div');
  1562. overlay.id = 'welcomeOverlay';
  1563. overlay.style.position = 'fixed';
  1564. overlay.style.top = '0';
  1565. overlay.style.left = '0';
  1566. overlay.style.width = '100vw'; // Adjusted width to viewport width
  1567. overlay.style.height = '100vh'; // Adjusted height to viewport height
  1568. overlay.style.backgroundColor = 'rgba(0, 0, 0, 1)'; // Initially black with full opacity
  1569. overlay.style.display = 'flex';
  1570. overlay.style.flexDirection = 'column';
  1571. overlay.style.alignItems = 'center';
  1572. overlay.style.justifyContent = 'center';
  1573. overlay.style.zIndex = '999999'; // Adjusted z-index to make sure it's in the foreground
  1574.  
  1575. const handEmoji = document.createElement('span');
  1576. handEmoji.style.fontSize = '48px';
  1577. handEmoji.textContent = '👋';
  1578. handEmoji.style.animation = 'wave 2s infinite'; // Apply animation to the hand emoji
  1579.  
  1580. const text = document.createElement('p');
  1581. text.style.fontSize = '24px';
  1582. text.style.color = 'green'; // Set initial color to green
  1583. text.textContent = 'Welcome Back!';
  1584. text.style.animation = 'sparkle 1s linear infinite'; // Apply animation to the text
  1585.  
  1586. overlay.appendChild(handEmoji);
  1587. overlay.appendChild(text);
  1588.  
  1589. document.body.appendChild(overlay);
  1590.  
  1591. // Add a black background to cover the entire screen
  1592. const body = document.querySelector('body');
  1593. body.style.overflow = 'hidden'; // Hide scrollbars
  1594. body.style.backgroundColor = 'black';
  1595.  
  1596. // Fade out the black overlay
  1597. setTimeout(() => {
  1598. overlay.style.transition = 'opacity 1s'; // Apply transition for opacity change
  1599. overlay.style.opacity = '0'; // Fade out the overlay
  1600. body.style.overflow = ''; // Restore scrollbars
  1601. body.style.backgroundColor = ''; // Restore background color
  1602. setTimeout(() => {
  1603. overlay.remove(); // Remove the overlay after fading out
  1604. }, 1000); // Delay removal to match the transition duration
  1605.  
  1606. // Trigger the menu animation to slide in instantly after the overlay has been hidden fully
  1607. triggerMenuAnimation();
  1608. }, 2000); // Delay the fade-out effect for 2 seconds
  1609. }
  1610. }
  1611.  
  1612.  
  1613.  
  1614. // menu items (can customise following the same structure as the others)
  1615. // const [variable name] = `<a href="[link]"> [name to show in menu] </a>`
  1616. const singleplayer = `<a href="/singleplayer"> Singleplayer </a>`
  1617. const party = `<a href="/play-with-friends"> Party </a>`
  1618. const quiz = `<a href="/quiz"> Quiz </a>`
  1619. const ongoingGames = `<a href="/me/current"> Ongoing Games </a>`
  1620. const activities = `<a href="/me/activities"> Activities </a>`
  1621. const likedMaps = `<a href="/me/likes"> Liked Maps </a>`
  1622. const newParty = `<a href=/party"> Party </a>`
  1623. const profile = `<a href=/me/profile"> Profile </a>`
  1624. const badges = `<a href=/me/badges"> Badges </a>`
  1625. const account = `<a href=/me/settings"> Account </a>`
  1626. const community = `<a href="/community"> Community </a>`
  1627. const explorer = `<a href="/explorer"> Explorer </a>`
  1628. const dailyChallenge = `<a href="/daily-challenges"> Daily Challenge </a>`
  1629. const streaks = `<a href="/streaks"> Streaks </a>`
  1630.  
  1631. // items to show in menu (can customise list using variable names defined above)
  1632. const items = [ likedMaps, dailyChallenge, explorer, streaks, ongoingGames, ]
  1633.  
  1634. // ======================================================================================================================================================
  1635.  
  1636. async function setup(items) {
  1637. await scanStyles();
  1638.  
  1639. const start = `<div class="` + cn("slanted-wrapper_root__") + ` ` + cn("slanted-wrapper_variantGrayTransparent__") + `">
  1640. <div class="` + cn("slanted-wrapper_start__") + ` ` + cn("slanted-wrapper_right__") + `"></div>
  1641. <div class="` + cn("page-label_labelWrapper__") + `">
  1642. <div style="--fs:var(--font-size-12);--lh:var(--line-height-12)" class="` + cn("label_label__") + `">`
  1643.  
  1644. const end = `</div></div><div class="` + cn("slanted-wrapper_end__") + ` ` + cn("slanted-wrapper_right__") + `"></div></div>`
  1645. let html = ""
  1646. for (let item of items) {
  1647. html = html + start + item + end
  1648. }
  1649.  
  1650. return html
  1651. }
  1652.  
  1653. const refresh = () => {
  1654. // only refreshes if not loading
  1655. if (document.querySelector("[class^='page-loading_loading__']")) return;
  1656.  
  1657. // if header exists
  1658. if (document.querySelector("[class^='header_header__']")) {
  1659. const header = document.querySelector("[class^='header_header__']")
  1660.  
  1661. // hides promos
  1662. if (document.querySelector("[class^='header_promoDealButtonWrapper__']")) {
  1663. document.querySelector("[class^='header_promoDealButtonWrapper__']").style.display = "none"
  1664. }
  1665.  
  1666. if (document.querySelector("[class^='header_pageLabel__']")) {
  1667. let menu = document.querySelector("[class^='header_pageLabel__07UxK']")
  1668. menu.style.display = "flex"
  1669.  
  1670. // hides old menu items
  1671. for (let child of menu.childNodes) {
  1672. if (!child.classList.contains("newItems")) {
  1673. child.style.display = "none"
  1674. }
  1675. }
  1676.  
  1677. // adds better menu items
  1678. if (document.querySelector(".newItems") === null) {
  1679. // creates new div from html
  1680. const newItems = document.createElement("div")
  1681. newItems.className = "newItems custom-menu-position" // Added custom class for positioning
  1682. setup(items).then(function(result) { newItems.innerHTML = result })
  1683. newItems.style.display = "flex"
  1684. // prepends new div
  1685. menu.prepend(newItems)
  1686. }
  1687.  
  1688. } else if (header.childNodes.length === 2) {
  1689.  
  1690. let menu = document.createElement("div")
  1691. menu.classList.add(cn("header_pageLabel__"))
  1692. menu.style.display = "flex"
  1693. header.childNodes[1].before(menu)
  1694. header.style.display = "flex"
  1695.  
  1696. // adds better menu items
  1697. if (document.querySelector(".newItems") === null) {
  1698. // creates new div from html
  1699. const newItems = document.createElement("div")
  1700. newItems.className = "newItems custom-menu-position" // Added custom class for positioning
  1701. setup(items).then(function(result) { newItems.innerHTML = result })
  1702. newItems.style.display = "flex"
  1703. // prepends new div
  1704. menu.prepend(newItems)
  1705. }
  1706. }
  1707.  
  1708. // highlights active menu item
  1709. if (document.querySelector(".newItems")) {
  1710. let url = window.location.href
  1711. const newItems = document.querySelector(".newItems")
  1712. for (let i = 0; i < newItems.childNodes.length; i++) {
  1713. let link = newItems.childNodes[i].querySelector("a")
  1714. link.style.color = "white"
  1715. newItems.childNodes[i].classList.remove(cn("slanted-wrapper_variantWhite__"))
  1716. newItems.childNodes[i].classList.add(cn("slanted-wrapper_variantGrayTransparent__"))
  1717. if (link.href == url) {
  1718. link.style.color = "#1a1a2e"
  1719. newItems.childNodes[i].classList.remove(cn("slanted-wrapper_variantGrayTransparent__"))
  1720. newItems.childNodes[i].classList.add(cn("slanted-wrapper_variantWhite__"))
  1721. }
  1722. }
  1723. }
  1724. }
  1725.  
  1726. // hides maprunner on home
  1727. if (document.querySelector("[class^='maprunner-start-page_content__']")) {
  1728. document.querySelector("[class^='maprunner-start-page_content__']").style.display = "none"
  1729. }
  1730. if (document.querySelector("[class^='maprunner-start-page_progress__']")) {
  1731. document.querySelector("[class^='maprunner-start-page_progress__']").style.display = "none"
  1732. }
  1733. if (document.querySelector("[class^='maprunner-class=signed-in-start-page_gradientPlate__A_ziw']")) {
  1734. document.querySelector("[class^='maprunner-signed-in-start-page_gradientPlate__']").style.display = "none"
  1735. }
  1736. if (document.querySelector("[class^='maprunner-signed-in-start-page_avatar__']")) {
  1737. document.querySelector("[class^='maprunner-signed-in-start-page_avatar__']").style.display = "none"
  1738. }
  1739.  
  1740. // hides footer on home
  1741. if (document.querySelector("[class^='footer_footer__']")) {
  1742. document.querySelector("[class^='footer_footer__']").style.display = "none"
  1743. }
  1744.  
  1745. // hides secondary menu on home
  1746. if (document.querySelector("[class^='secondary-menu_menu__']") && !document.querySelector("[class^='pop-out-main-menu_wrapper__']")) {
  1747. document.querySelector("[class^='secondary-menu_menu__']").style.display = "none"
  1748. }
  1749.  
  1750. // hides ongoing games on home
  1751. if (document.querySelector("[class^='primary-menu_continuePlaying__']")) {
  1752. document.querySelector("[class^='primary-menu_continuePlaying__']").style.display = "none"
  1753. }
  1754.  
  1755. // hides daily challenge on home
  1756. if (document.querySelector("[class^='play-daily-badge_cardWrapper__']")) {
  1757. document.querySelector("[class^='play-daily-badge_cardWrapper__']").style.display = "none"
  1758. }
  1759. if (document.querySelector("[class^='play-daily-badge_badgeCanvas__']")) {
  1760. document.querySelector("[class^='play-daily-badge_badgeCanvas__']").style.display = "none"
  1761. }
  1762.  
  1763. if (document.querySelector("[class^='happy-holidays-button_root__']")) {
  1764. document.querySelector("[class^='happy-holidays-button_root__']").style.display = "none"
  1765. }
  1766.  
  1767. }
  1768.  
  1769. let observer4 = new MutationObserver((mutations) => {
  1770. refresh();
  1771. });
  1772.  
  1773. observer4.observe(document.body, {
  1774. characterDataOldValue: false,
  1775. subtree: true,
  1776. childList: true,
  1777. characterData: false
  1778. });
  1779.  
  1780.  
  1781.  
  1782. // Function to trigger the menu animation to slide in
  1783. function triggerMenuAnimation() {
  1784. // Define CSS animation for the primary menu wrapper
  1785. const menuAnimation = `
  1786. @keyframes slideIn {
  1787. 0% { transform: translateX(-100%); }
  1788. 100% { transform: translateX(0); }
  1789. }
  1790.  
  1791. .primary-menu_wrapper__3ahEU {
  1792. animation: slideIn 1s forwards; /* Apply the animation without delay */
  1793. }
  1794. `;
  1795.  
  1796. // Append menu animation styles to existing styleElement
  1797. const styleElement = document.createElement('style');
  1798. styleElement.textContent = menuAnimation;
  1799. document.head.appendChild(styleElement);
  1800. }
  1801.  
  1802. // Function to observe changes in the DOM and trigger menu animation when primary menu wrapper is present
  1803. function observeMenuWrapper() {
  1804. const menuWrapper = document.querySelector('.primary-menu_wrapper__3ahEU');
  1805. if (menuWrapper) {
  1806. triggerMenuAnimation();
  1807. }
  1808. }
  1809.  
  1810. // Function to setup the MutationObserver to observe changes in the DOM
  1811. function setupObserver() {
  1812. const observer = new MutationObserver((mutations) => {
  1813. observeMenuWrapper();
  1814. });
  1815.  
  1816. observer.observe(document.body, {
  1817. characterDataOldValue: false,
  1818. subtree: true,
  1819. childList: true,
  1820. characterData: false
  1821. });
  1822. }
  1823.  
  1824. // Call the function to setup the MutationObserver
  1825. setupObserver();
  1826.  
  1827. // Call the function to trigger the menu animation when the DOM content is fully loaded
  1828. document.addEventListener('DOMContentLoaded', () => {
  1829. triggerMenuAnimation();
  1830. });
  1831.  
  1832. // Function to handle key press event
  1833. function handleKeyPress(event) {
  1834. // Check if the pressed key is the Escape key (key code 27)
  1835. if (event.keyCode === 27) {
  1836. // Trigger the back button element
  1837. const backButtonWrapper = document.querySelector('.back-button_contentWrapper__GN8_N');
  1838. if (backButtonWrapper) {
  1839. backButtonWrapper.click(); // Simulate a click event on the back button wrapper element
  1840. }
  1841. }
  1842. }
  1843.  
  1844. // Add event listener for key press events on the document
  1845. document.addEventListener('keydown', handleKeyPress);
  1846.  
  1847. // Call the function to add the overlay only when the script runs
  1848. addWelcomeOverlay();
  1849.  
  1850. // Update CSS animation for the hand emoji
  1851. const existingStyleElement = document.querySelector('style');
  1852. if (existingStyleElement) {
  1853. existingStyleElement.textContent += `
  1854. @keyframes wave {
  1855. 0% { transform: rotate(0deg); }
  1856. 10% { transform: rotate(-10deg); }
  1857. 20% { transform: rotate(10deg); }
  1858. 30% { transform: rotate(-10deg); }
  1859. 40% { transform: rotate(10deg); }
  1860. 50% { transform: rotate(-10deg); }
  1861. 60% { transform: rotate(10deg); }
  1862. 70% { transform: rotate(-10deg); }
  1863. 80% { transform: rotate(10deg); }
  1864. 90% { transform: rotate(-10deg); }
  1865. 100% { transform: rotate(0deg); }
  1866. }
  1867.  
  1868. @keyframes sparkle {
  1869. 0% { color: green; }
  1870. 50% { color: white; }
  1871. 100% { color: green; }
  1872. }
  1873. `;
  1874. }
  1875.  
  1876. // Call the function to add the overlay when the script runs
  1877. addWelcomeOverlay();
  1878.  
  1879.  
  1880. /////////////////// faster map closing and opening //////////////////////////
  1881.  
  1882. let activeClass;
  1883.  
  1884. function main1() {
  1885. new MutationObserver(() => {
  1886. const guessMap = document.querySelector(
  1887. "[data-qa='guess-map']:not([data-skip])",
  1888. );
  1889.  
  1890. if (!guessMap) return;
  1891.  
  1892. guessMap.setAttribute("data-skip", "");
  1893.  
  1894. guessMap.addEventListener("mouseenter", () => {
  1895. if (activeClass && !isPinned()) {
  1896. guessMap.classList.add(activeClass);
  1897. }
  1898. });
  1899.  
  1900. guessMap.addEventListener("mouseleave", () => {
  1901. activeClass = guessMap.classList.item(guessMap.classList.length - 1);
  1902.  
  1903. if (!isPinned()) {
  1904. guessMap.classList.remove(activeClass);
  1905. }
  1906. });
  1907. }).observe(document.body, { childList: true, subtree: true });
  1908. }
  1909.  
  1910. function isPinned() {
  1911. const pinButton = document.querySelector(
  1912. "[data-qa='guess-map__control--sticky-active']",
  1913. );
  1914.  
  1915. let pinned;
  1916.  
  1917. if (pinButton) {
  1918. pinButton.classList.forEach((cls) => {
  1919. if (cls.includes("Active")) {
  1920. pinned = true;
  1921. }
  1922. });
  1923. }
  1924.  
  1925. return pinned;
  1926. }
  1927.  
  1928. main1();
  1929.  
  1930.  
  1931. /////////////////// END //////////////////////////
  1932.  
  1933. // menu items (can customise following the same structure as the others)
  1934. // const [variable name] = `<a href="[link]"> [name to show in menu] </a>`
  1935.  
  1936.  
  1937. ////////////////////////////// Blurring and unblurring email and important things for streaming //////////////////////////////////
  1938.  
  1939. // Create a style element
  1940. let style = document.createElement('style');
  1941.  
  1942. // Define CSS rules with initial blur
  1943. style.innerHTML = `
  1944. .blurred {
  1945. filter: blur(5px) !important;
  1946. }
  1947. .invite-modal_blurred {
  1948. filter: blur(10px) !important;
  1949. }
  1950. .qr-blurred {
  1951. filter: blur(8px) !important;
  1952. }
  1953. `;
  1954.  
  1955. // Append the style element to the document body
  1956. document.body.appendChild(style);
  1957.  
  1958. // Function to add blur class to elements
  1959. function addBlurClass() {
  1960. // Select all elements that need to be blurred
  1961. const elementsToBlur = document.querySelectorAll('.edit-profile__section div[class^="form-field_formField__"] div p, input[name="email"][data-qa="email-field"], input[name="repeatEmail"], span[class^="copy-link_root__"] input, [class*="invite-modal_section__"]:nth-child(3):nth-child(3), [class*="invite-modal_qr__"]');
  1962.  
  1963. // Loop through the selected elements
  1964. elementsToBlur.forEach(element => {
  1965. element.classList.add('blurred');
  1966. if (element.classList.contains('invite-modal_section__')) {
  1967. element.classList.add('invite-modal_blurred');
  1968. }
  1969. if (element.classList.contains('invite-modal_qr__')) {
  1970. element.classList.add('qr-blurred');
  1971. }
  1972. });
  1973. }
  1974.  
  1975. // Function to remove blur class from elements
  1976. function removeBlurClass() {
  1977. // Select all elements that need to be unblurred
  1978. const elementsToUnblur = document.querySelectorAll('.edit-profile__section div[class^="form-field_formField__"] div p, input[name="email"][data-qa="email-field"], input[name="repeatEmail"], span[class^="copy-link_root__"] input, [class*="invite-modal_section__"]:nth-child(3):nth-child(3), [class*="invite-modal_qr__"]');
  1979.  
  1980. // Loop through the selected elements
  1981. elementsToUnblur.forEach(element => {
  1982. element.classList.remove('blurred');
  1983. element.classList.remove('invite-modal_blurred');
  1984. element.classList.remove('qr-blurred');
  1985. });
  1986. }
  1987.  
  1988. // Function to reapply blur effect to elements
  1989. function reapplyBlurEffect() {
  1990. addBlurClass();
  1991. }
  1992.  
  1993. // Use MutationObserver to continuously monitor the DOM for changes
  1994. const observer5 = new MutationObserver(reapplyBlurEffect);
  1995. observer5.observe(document.body, { childList: true, subtree: true });
  1996.  
  1997. // Call the function to initially blur elements
  1998. addBlurClass();
  1999.  
  2000. // Function to handle mouseover event
  2001. function handleMouseover(event) {
  2002. const target = event.target;
  2003. target.classList.remove('blurred');
  2004. if (target.classList.contains('invite-modal_section__')) {
  2005. target.classList.remove('invite-modal_blurred');
  2006. }
  2007. if (target.classList.contains('invite-modal_qr__')) {
  2008. target.classList.remove('qr-blurred');
  2009. }
  2010. }
  2011.  
  2012. // Function to handle mouseout event
  2013. function handleMouseout(event) {
  2014. const target = event.target;
  2015. target.classList.add('blurred');
  2016. if (target.classList.contains('invite-modal_section__')) {
  2017. target.classList.add('invite-modal_blurred');
  2018. }
  2019. if (target.classList.contains('invite-modal_qr__')) {
  2020. target.classList.add('qr-blurred');
  2021. }
  2022. }
  2023.  
  2024. // Add mouseover and mouseout event listeners to each element
  2025. document.querySelectorAll('.edit-profile__section div[class^="form-field_formField__"] div p, input[name="email"][data-qa="email-field"], input[name="repeatEmail"], span[class^="copy-link_root__"] input, [class*="invite-modal_section__"]:nth-child(3):nth-child(3), [class*="invite-modal_qr__"]').forEach(element => {
  2026. element.addEventListener('mouseover', handleMouseover);
  2027. element.addEventListener('mouseout', handleMouseout);
  2028. });
  2029.  
  2030. // Reapply blur effect when the URL hash changes
  2031. window.addEventListener('hashchange', reapplyBlurEffect);
  2032.  
  2033. // Remove blur effect when navigating back to the main menu of the game
  2034. document.addEventListener('keydown', function(event) {
  2035. if (event.key === "Escape") {
  2036. removeBlurClass();
  2037. }
  2038. });
  2039. ////////////////////////////// END //////////////////////////////////
  2040.  
  2041.  
  2042.  
  2043.  
  2044.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址