Survev UI Mod v4

QoL features for Survev.io

  1. // ==UserScript==
  2. // @name Survev UI Mod v4
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-08-31
  5. // @description QoL features for Survev.io
  6. // @author Blubbled
  7. // @match https://survev.io/*
  8. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13.  
  14.  
  15. (function() {
  16.  
  17. var lastCalledTime;
  18. var fps;
  19. var frameTimes = [];
  20. var maxFrames = 100;
  21. var uncappedFPS = false;
  22. var uiElementsEnabled = true;
  23. var fpsCounterEnabled = true;
  24. var currentCountdown = null;
  25.  
  26. var customColor = localStorage.getItem('customColor') || '#ffffff';
  27. var colorToggleState = localStorage.getItem('colorToggle') === 'true';
  28.  
  29. function requestAnimFrame() {
  30. if (!lastCalledTime) {
  31. lastCalledTime = Date.now();
  32. fps = 0;
  33. return;
  34. }
  35.  
  36. var currentTime = Date.now();
  37. var delta = (currentTime - lastCalledTime) / 1000;
  38. lastCalledTime = currentTime;
  39.  
  40. frameTimes.push(delta);
  41.  
  42. if (frameTimes.length > maxFrames) {
  43. frameTimes.shift();
  44. }
  45.  
  46. var totalTime = frameTimes.reduce((sum, time) => sum + time, 0);
  47. fps = (frameTimes.length / totalTime).toFixed(0);
  48. }
  49.  
  50. function createFPSCounter() {
  51. var fpsCounter = document.createElement('div');
  52. fpsCounter.id = 'fps-counter';
  53. fpsCounter.style.position = 'fixed';
  54. fpsCounter.style.left = '10px';
  55. fpsCounter.style.top = '130px';
  56. fpsCounter.style.color = customColor;
  57. fpsCounter.style.fontSize = '20px';
  58. fpsCounter.style.fontWeight = 'bold';
  59. fpsCounter.style.zIndex = '1000';
  60. fpsCounter.style.backgroundColor = 'rgba(0, 0, 0, 0)';
  61. fpsCounter.style.padding = '5px';
  62. fpsCounter.style.borderRadius = '5px';
  63. document.body.appendChild(fpsCounter);
  64.  
  65. var lastUpdate = Date.now();
  66.  
  67. function updateFPSCounter() {
  68. requestAnimFrame();
  69. var now = Date.now();
  70. if (now - lastUpdate >= 1000) {
  71. fpsCounter.textContent = `FPS: ${fps}`;
  72. lastUpdate = now;
  73. }
  74.  
  75. requestAnimationFrame(updateFPSCounter);
  76. }
  77.  
  78. updateFPSCounter();
  79. }
  80.  
  81. createFPSCounter();
  82.  
  83. function toggleFPSCounter(enabled) {
  84. var fpsCounter = document.getElementById('fps-counter');
  85. if (enabled) {
  86. fpsCounter.style.display = 'block';
  87. } else {
  88. fpsCounter.style.display = 'none';
  89. }
  90. }
  91.  
  92. function updateTextColor(newColor) {
  93. customColor = newColor;
  94. localStorage.setItem('customColor', newColor);
  95.  
  96. var fpsCounter = document.getElementById('fps-counter');
  97. var ammoCount = document.getElementById('ui-current-clip');
  98. var healCounts = document.querySelectorAll('.ui-loot-count');
  99.  
  100. if (fpsCounter) fpsCounter.style.color = newColor;
  101. if (ammoCount) ammoCount.style.color = newColor;
  102. healCounts.forEach(function(healCount) {
  103. healCount.style.color = newColor;
  104. });
  105. }
  106.  
  107. function applyInitialTextColor() {
  108. var ammoCount = document.getElementById('ui-current-clip');
  109. var healCounts = document.querySelectorAll('.ui-loot-count');
  110.  
  111. if (ammoCount) ammoCount.style.color = customColor;
  112. healCounts.forEach(function(healCount) {
  113. healCount.style.color = customColor;
  114. });
  115. }
  116.  
  117. function applyColorOnGameUI() {
  118. var observer = new MutationObserver(function(mutations) {
  119. mutations.forEach(function(mutation) {
  120. if (mutation.addedNodes.length) {
  121.  
  122. applyInitialTextColor();
  123. }
  124. });
  125. });
  126.  
  127. observer.observe(document.body, { childList: true, subtree: true });
  128. }
  129. var uiTopLeft = document.getElementById('ui-top-left');
  130. if (uiTopLeft) {
  131. uiTopLeft.style.position = 'relative';
  132. uiTopLeft.style.left = '100px';
  133. }
  134.  
  135. document.addEventListener("DOMContentLoaded", function() {
  136. if (colorToggleState) {
  137. applyInitialTextColor();
  138. }
  139.  
  140. applyColorOnGameUI();
  141. });
  142.  
  143. var settingsButton = document.createElement('button');
  144. settingsButton.id = 'settings-button';
  145. settingsButton.textContent = 'Mod Settings';
  146. settingsButton.style.position = 'fixed';
  147. settingsButton.style.left = '10px';
  148. settingsButton.style.top = '50%';
  149. settingsButton.style.transform = 'translateY(-50%)';
  150. settingsButton.style.padding = '10px';
  151. settingsButton.style.fontSize = '18px';
  152. settingsButton.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  153. settingsButton.style.color = 'white';
  154. settingsButton.style.zIndex = '1000';
  155. settingsButton.style.display = 'none';
  156. document.body.appendChild(settingsButton);
  157.  
  158. var settingsTab = document.createElement('div');
  159. settingsTab.id = 'settings-tab';
  160. settingsTab.style.position = 'fixed';
  161. settingsTab.style.left = '200px';
  162. settingsTab.style.top = '50%';
  163. settingsTab.style.width = '300px';
  164. settingsTab.style.height = '400px';
  165. settingsTab.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  166. settingsTab.style.color = 'white';
  167. settingsTab.style.padding = '20px';
  168. settingsTab.style.borderRadius = '10px';
  169. settingsTab.style.display = 'none';
  170. settingsTab.innerHTML = '<h2>Mod Settings (buggy, reenable uncapped FPS a few times if cursor info doesnt update)</h2>';
  171. document.body.appendChild(settingsTab);
  172.  
  173. var fpsCheckbox = document.createElement('input');
  174. fpsCheckbox.type = 'checkbox';
  175. fpsCheckbox.id = 'uncapped-fps-checkbox';
  176. var fpsLabel = document.createElement('label');
  177. fpsLabel.setAttribute('for', 'uncapped-fps-checkbox');
  178. fpsLabel.textContent = 'Enable Uncapped FPS';
  179. settingsTab.appendChild(fpsCheckbox);
  180. settingsTab.appendChild(fpsLabel);
  181. settingsTab.appendChild(document.createElement('br'));
  182.  
  183.  
  184. function toggleUncappedFPS(enabled) {
  185. if (enabled) {
  186. window.requestAnimationFrame = function(callback) {
  187. return setTimeout(callback, 1);
  188. };
  189. } else {
  190. window.requestAnimationFrame = function(callback) {
  191. return setTimeout(callback, 1000 / 60);
  192. };
  193. }
  194. }
  195.  
  196.  
  197. var uiCheckbox = document.createElement('input');
  198. uiCheckbox.type = 'checkbox';
  199. uiCheckbox.id = 'ui-elements-checkbox';
  200. var uiLabel = document.createElement('label');
  201. uiLabel.setAttribute('for', 'ui-elements-checkbox');
  202. uiLabel.textContent = 'Show Cursor Info';
  203. settingsTab.appendChild(uiCheckbox);
  204. settingsTab.appendChild(uiLabel);
  205. settingsTab.appendChild(document.createElement('br'));
  206.  
  207. var fpsCounterCheckbox = document.createElement('input');
  208. fpsCounterCheckbox.type = 'checkbox';
  209. fpsCounterCheckbox.id = 'fps-counter-checkbox';
  210. var fpsCounterLabel = document.createElement('label');
  211. fpsCounterLabel.setAttribute('for', 'fps-counter-checkbox');
  212. fpsCounterLabel.textContent = 'Show FPS Counter';
  213. settingsTab.appendChild(fpsCounterCheckbox);
  214. settingsTab.appendChild(fpsCounterLabel);
  215. settingsTab.appendChild(document.createElement('br'));
  216.  
  217. var colorToggleLabel = document.createElement('label');
  218. colorToggleLabel.textContent = 'Enable Custom Text Color';
  219. settingsTab.appendChild(colorToggleLabel);
  220.  
  221. var colorToggleCheckbox = document.createElement('input');
  222. colorToggleCheckbox.type = 'checkbox';
  223. colorToggleCheckbox.id = 'color-toggle-checkbox';
  224. colorToggleCheckbox.checked = colorToggleState;
  225. settingsTab.appendChild(colorToggleCheckbox);
  226. settingsTab.appendChild(document.createElement('br'));
  227.  
  228. var colorPickerLabel = document.createElement('label');
  229. colorPickerLabel.textContent = 'Select Text Color';
  230. settingsTab.appendChild(colorPickerLabel);
  231.  
  232. var colorPicker = document.createElement('input');
  233. colorPicker.type = 'color';
  234. colorPicker.value = customColor;
  235. colorPicker.disabled = !colorToggleState;
  236. settingsTab.appendChild(colorPicker);
  237. settingsTab.appendChild(document.createElement('br'));
  238.  
  239. colorToggleCheckbox.addEventListener('change', function() {
  240. if (colorToggleCheckbox.checked) {
  241. colorPicker.disabled = false;
  242. updateTextColor(colorPicker.value);
  243. } else {
  244. colorPicker.disabled = true;
  245. updateTextColor('#ffffff');
  246. }
  247. localStorage.setItem('colorToggle', colorToggleCheckbox.checked);
  248. });
  249.  
  250.  
  251. colorPicker.addEventListener('input', function() {
  252. updateTextColor(colorPicker.value);
  253. });
  254.  
  255. function updateSettingsButtonVisibility() {
  256. var loadingOverlay = document.querySelector('.play-loading-outer');
  257.  
  258. if (loadingOverlay && window.getComputedStyle(loadingOverlay).opacity === '0') {
  259. settingsButton.style.display = 'block';
  260. } else {
  261. settingsButton.style.display = 'none';
  262. settingsTab.style.display = 'none';
  263. }
  264. }
  265.  
  266. setInterval(updateSettingsButtonVisibility, 100);
  267.  
  268. settingsButton.addEventListener('click', function() {
  269. if (settingsTab.style.display === 'none') {
  270. settingsTab.style.display = 'block';
  271. } else {
  272. settingsTab.style.display = 'none';
  273. }
  274. });
  275.  
  276. function loadSettings() {
  277. var uncappedFPSSetting = localStorage.getItem('uncappedFPS') === 'true';
  278. var uiElementsSetting = localStorage.getItem('uiElementsEnabled') === 'true';
  279. var fpsCounterSetting = localStorage.getItem('fpsCounterEnabled') === 'true';
  280.  
  281. fpsCheckbox.checked = uncappedFPSSetting;
  282. uiCheckbox.checked = uiElementsSetting;
  283. fpsCounterCheckbox.checked = fpsCounterSetting;
  284.  
  285. toggleUncappedFPS(uncappedFPSSetting);
  286. toggleUIElementDisplay(uiElementsSetting);
  287. toggleFPSCounter(fpsCounterSetting);
  288.  
  289. if (colorToggleState) {
  290. updateTextColor(customColor);
  291. } else {
  292. updateTextColor('#ffffff');
  293. }
  294. }
  295.  
  296. function saveSettings() {
  297. var uncappedFPSSetting = fpsCheckbox.checked;
  298. var uiElementsSetting = uiCheckbox.checked;
  299. var fpsCounterSetting = fpsCounterCheckbox.checked;
  300.  
  301. localStorage.setItem('uncappedFPS', uncappedFPSSetting);
  302. localStorage.setItem('uiElementsEnabled', uiElementsSetting);
  303. localStorage.setItem('fpsCounterEnabled', fpsCounterSetting);
  304.  
  305. toggleUncappedFPS(uncappedFPSSetting);
  306. toggleUIElementDisplay(uiElementsSetting);
  307. toggleFPSCounter(fpsCounterSetting);
  308. }
  309.  
  310. loadSettings();
  311.  
  312. fpsCheckbox.addEventListener('change', saveSettings);
  313. uiCheckbox.addEventListener('change', saveSettings);
  314. fpsCounterCheckbox.addEventListener('change', saveSettings);
  315.  
  316.  
  317. var gunSwitchDelayMap = {
  318. "AWM-S": 1000,
  319. "BLR 81": 1000,
  320. "Model 94": 1000,
  321. "Mosin-Nagant": 1000,
  322. "SV-98": 1000,
  323. "Scout Elite": 1000,
  324.  
  325. "Hawk 12G": 900,
  326. "Heart Cannon": 900,
  327. "M1100": 900,
  328. "M134": 900,
  329. "M79": 900,
  330. "M870": 900,
  331. "Potato Cannon": 900,
  332.  
  333. "AK-47": 750,
  334. "AN-94": 750,
  335. "BAR M1918": 750,
  336. "CZ-3A1": 750,
  337. "DP-28": 750,
  338. "FAMAS": 750,
  339. "Groza": 750,
  340. "Groza-S": 750,
  341. "L86A2": 750,
  342. "M1 Garand": 750,
  343. "M1014": 750,
  344. "M1A1": 750,
  345. "M249": 750,
  346. "M39 EMR": 750,
  347. "M416": 750,
  348. "M4A1-S": 750,
  349. "MAC-10": 750,
  350. "MP5": 750,
  351. "Mk 12 SPR": 750,
  352. "Mk45G": 750,
  353. "PKM": 750,
  354. "PKP Pecheneg": 750,
  355. "QBB-97": 750,
  356. "SCAR-H": 750,
  357. "SCAR-SSR": 750,
  358. "SPAS-12": 750,
  359. "SVD-63": 750,
  360. "Saiga-12": 750,
  361. "Spud Gun": 750,
  362. "UMP9": 750,
  363. "USAS-12": 750,
  364. "VSS": 750,
  365. "Vector": 750,
  366.  
  367. "Bugle": 300,
  368. "DEagle 50": 300,
  369. "Dual DEagle 50": 300,
  370. "Dual Flare Gun": 300,
  371. "Dual OT-38": 300,
  372. "Dual OTs-38": 300,
  373. "Dual P30L": 300,
  374. "Dual Peacemaker": 300,
  375. "Flare Gun": 300,
  376. "MP220": 300,
  377. "OT-38": 300,
  378. "OTs-38": 300,
  379. "Peacemaker": 300,
  380. "Rainbow Blaster": 300,
  381.  
  382. "Dual G18C": 250,
  383. "Dual M1911": 250,
  384. "Dual M9": 250,
  385. "Dual M93R": 250,
  386. "G18C": 250,
  387. "M1911": 250,
  388. "M9": 250,
  389. "M9 Cursed": 250,
  390. "M93R": 250,
  391. "P30L": 250
  392. };
  393.  
  394.  
  395. var currentCountdown = null;
  396.  
  397. function createSwitchDelayText() {
  398. var delayText = document.createElement('div');
  399. delayText.id = 'switch-delay-text';
  400. delayText.style.position = 'fixed';
  401. delayText.style.color = 'red';
  402. delayText.style.fontSize = '25px';
  403. delayText.style.fontWeight = 'bold';
  404. delayText.style.zIndex = '1000';
  405. delayText.style.left = '50%';
  406. delayText.style.transform = 'translateX(-50%)';
  407. delayText.style.top = '40%';
  408. document.body.appendChild(delayText);
  409. return delayText;
  410. }
  411.  
  412.  
  413. function showSwitchDelay(gunName, delayMs) {
  414. if (currentCountdown) {
  415. clearInterval(currentCountdown);
  416. }
  417.  
  418.  
  419. if (!gunSwitchDelayMap[gunName]) {
  420. return;
  421. }
  422.  
  423. var delayInSeconds = (delayMs / 1000).toFixed(2);
  424. var delayText = document.getElementById('switch-delay-text') || createSwitchDelayText();
  425.  
  426. delayText.textContent = `${delayInSeconds}s`;
  427. delayText.style.display = 'block';
  428.  
  429. currentCountdown = setInterval(function() {
  430. delayInSeconds -= 0.01;
  431. delayText.textContent = `${delayInSeconds.toFixed(2)}s`;
  432.  
  433. if (delayInSeconds <= 0) {
  434. clearInterval(currentCountdown);
  435. delayText.style.display = 'none';
  436. currentCountdown = null;
  437. }
  438. }, 10);
  439. }
  440.  
  441.  
  442. function detectWeaponSwitch() {
  443. var previousWeapon = null;
  444.  
  445. setInterval(function() {
  446. var equippedWeapon = document.querySelector('.ui-weapon-switch[style*="background-color: rgba(0, 0, 0, 0.4)"], .ui-weapon-switch[style*="opacity: 1"]');
  447. if (equippedWeapon) {
  448. var weaponName = equippedWeapon.querySelector('.ui-weapon-name').textContent.trim();
  449. if (weaponName !== previousWeapon) {
  450. previousWeapon = weaponName;
  451.  
  452. var delayMs = gunSwitchDelayMap[weaponName];
  453. if (delayMs) {
  454. showSwitchDelay(weaponName, delayMs);
  455. }
  456. }
  457. }
  458. }, 100);
  459. }
  460.  
  461. detectWeaponSwitch();
  462.  
  463.  
  464. function periodicallyShowKillCounter() {
  465. showKillCounter();
  466. setTimeout(periodicallyShowKillCounter, 100);
  467. }
  468.  
  469. function showKillCounter() {
  470. var killCounter = document.getElementById('ui-kill-counter-wrapper');
  471. if (killCounter) {
  472. killCounter.style.display = 'block';
  473. killCounter.style.position = 'fixed';
  474. killCounter.style.left = '5px';
  475. killCounter.style.top = '-25px';
  476. killCounter.style.color = 'white';
  477. killCounter.style.fontSize = '20px';
  478. killCounter.style.fontWeight = 'bold';
  479. killCounter.style.zIndex = '1000';
  480. killCounter.style.backgroundColor = 'rgba(0, 0, 0, 0)';
  481. killCounter.style.padding = '5px';
  482. killCounter.style.borderRadius = '5px';
  483.  
  484. var counterText = killCounter.querySelector('.counter-text');
  485. if (counterText) {
  486. counterText.style.minWidth = '30px';
  487. }
  488. }
  489. }
  490.  
  491. function calculateAverageBoostWidth() {
  492. var counterLengths = [98.5, 98.5, 147.75, 49.25];
  493. var boostCounters = document.querySelectorAll('#ui-boost-counter .ui-bar-inner');
  494. var totalWidth = 0;
  495.  
  496. boostCounters.forEach(function(counter, index) {
  497. var widthPercentage = parseFloat(counter.style.width);
  498. var unitLength = counterLengths[index];
  499. totalWidth += (widthPercentage / 100) * unitLength;
  500. });
  501.  
  502. var totalUnitLength = counterLengths.reduce((a, b) => a + b, 0);
  503. var averageWidthPercentage = (totalWidth / totalUnitLength) * 100;
  504.  
  505. return averageWidthPercentage.toFixed(2) + "%";
  506. }
  507.  
  508. function toggleUIElementDisplay(enabled) {
  509. if (enabled) {
  510.  
  511. var healthBarWidthCopy = document.createElement('span');
  512. healthBarWidthCopy.id = 'health-bar-width-copy';
  513. healthBarWidthCopy.classList.add('unselectable');
  514. healthBarWidthCopy.style.position = 'fixed';
  515. healthBarWidthCopy.style.fontSize = '25px';
  516. healthBarWidthCopy.style.fontWeight = 'bold';
  517. healthBarWidthCopy.style.display = 'none';
  518.  
  519. var ammoCountCopy = document.createElement('span');
  520. ammoCountCopy.id = 'ammo-count-copy';
  521. ammoCountCopy.classList.add('unselectable');
  522. ammoCountCopy.style.position = 'fixed';
  523. ammoCountCopy.style.fontSize = '25px';
  524. ammoCountCopy.style.fontWeight = 'bold';
  525. ammoCountCopy.style.display = 'none';
  526.  
  527. var weaponNameCopy = document.createElement('span');
  528. weaponNameCopy.id = 'weapon-name-copy';
  529. weaponNameCopy.classList.add('unselectable');
  530. weaponNameCopy.style.position = 'fixed';
  531. weaponNameCopy.style.fontSize = '20px';
  532. weaponNameCopy.style.fontWeight = 'bold';
  533. weaponNameCopy.style.display = 'none';
  534.  
  535. var boostWidthCopy = document.createElement('span');
  536. boostWidthCopy.id = 'boost-width-copy';
  537. boostWidthCopy.classList.add('unselectable');
  538. boostWidthCopy.style.position = 'fixed';
  539. boostWidthCopy.style.fontSize = '20px';
  540. boostWidthCopy.style.fontWeight = 'bold';
  541. boostWidthCopy.style.color = 'orange';
  542. boostWidthCopy.style.display = 'none';
  543.  
  544. function updateHealthBarWidthCopy() {
  545. var healthBar = document.getElementById('ui-health-actual');
  546. if (healthBar && healthBar.offsetWidth > 0 && healthBar.offsetHeight > 0) {
  547. var healthBarWidth = Math.round(parseFloat(healthBar.style.width));
  548. var healthBarColor = healthBar.style.backgroundColor;
  549.  
  550. healthBarWidthCopy.textContent = healthBarWidth + "%";
  551. healthBarWidthCopy.style.color = healthBarColor;
  552. healthBarWidthCopy.style.display = 'block';
  553. } else {
  554. healthBarWidthCopy.style.display = 'none';
  555. }
  556. }
  557.  
  558. function updateAmmoCountCopy() {
  559. var ammoCountElement = document.getElementById('ui-current-clip');
  560.  
  561. if (ammoCountElement && window.getComputedStyle(ammoCountElement).display !== 'none' && parseFloat(window.getComputedStyle(ammoCountElement).opacity) > 0) {
  562. var ammoCount = ammoCountElement.textContent;
  563. ammoCountCopy.textContent = ammoCount;
  564. ammoCountCopy.style.color = ammoCountElement.style.color;
  565. ammoCountCopy.style.display = 'block';
  566. } else {
  567. ammoCountCopy.style.display = 'none';
  568. }
  569. }
  570.  
  571. function updateWeaponNameCopy() {
  572. var equippedWeapon = document.querySelector('.ui-weapon-switch[style*="background-color: rgba(0, 0, 0, 0.4)"], .ui-weapon-switch[style*="opacity: 1"]');
  573. if (equippedWeapon) {
  574. var weaponName = equippedWeapon.querySelector('.ui-weapon-name').textContent;
  575. weaponNameCopy.textContent = weaponName;
  576. weaponNameCopy.style.color = 'white';
  577. weaponNameCopy.style.display = 'block';
  578. } else {
  579. weaponNameCopy.style.display = 'none';
  580. }
  581. }
  582.  
  583. function updateBoostWidthCopy() {
  584. var boostElement = document.getElementById('ui-boost-counter');
  585. if (boostElement && window.getComputedStyle(boostElement).display !== 'none' && parseFloat(window.getComputedStyle(boostElement).opacity) > 0) {
  586. var averageBoostWidth = calculateAverageBoostWidth();
  587. boostWidthCopy.textContent = averageBoostWidth;
  588. boostWidthCopy.style.display = 'block';
  589. } else {
  590. boostWidthCopy.style.display = 'none';
  591. }
  592. }
  593.  
  594. function followCursor(event) {
  595. healthBarWidthCopy.style.left = `${event.clientX - 70}px`;
  596. healthBarWidthCopy.style.top = `${event.clientY + 25}px`;
  597.  
  598. ammoCountCopy.style.left = `${event.clientX + 40}px`;
  599. ammoCountCopy.style.top = `${event.clientY + 25}px`;
  600.  
  601. weaponNameCopy.style.left = `${event.clientX + 40}px`;
  602. weaponNameCopy.style.top = `${event.clientY + 50}px`;
  603.  
  604. boostWidthCopy.style.left = `${event.clientX - 70}px`;
  605. boostWidthCopy.style.top = `${event.clientY + 50}px`;
  606. }
  607.  
  608. document.addEventListener('mousemove', followCursor);
  609.  
  610. healthBarWidthCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
  611. healthBarWidthCopy.style.webkitUserSelect = 'none'; /* Safari */
  612. healthBarWidthCopy.style.userSelect = 'none'; /* Standard syntax */
  613.  
  614. ammoCountCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
  615. ammoCountCopy.style.webkitUserSelect = 'none'; /* Safari */
  616. ammoCountCopy.style.userSelect = 'none'; /* Standard syntax */
  617.  
  618. weaponNameCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
  619. weaponNameCopy.style.webkitUserSelect = 'none'; /* Safari */
  620. weaponNameCopy.style.userSelect = 'none'; /* Standard syntax */
  621.  
  622. boostWidthCopy.style.webkitTouchCallout = 'none'; /* iOS Safari */
  623. boostWidthCopy.style.webkitUserSelect = 'none'; /* Safari */
  624. boostWidthCopy.style.userSelect = 'none'; /* Standard syntax */
  625.  
  626. document.body.appendChild(healthBarWidthCopy);
  627. document.body.appendChild(ammoCountCopy);
  628. document.body.appendChild(weaponNameCopy);
  629. document.body.appendChild(boostWidthCopy);
  630.  
  631. updateHealthBarWidthCopy();
  632. updateAmmoCountCopy();
  633. updateWeaponNameCopy();
  634. updateBoostWidthCopy();
  635.  
  636. var healthObserver = new MutationObserver(updateHealthBarWidthCopy);
  637. var healthTargetNode = document.getElementById('ui-health-actual');
  638. if (healthTargetNode) {
  639. healthObserver.observe(healthTargetNode, { attributes: true, attributeFilter: ['style', 'class'] });
  640. }
  641. if (healthTargetNode && healthTargetNode.parentElement) {
  642. healthObserver.observe(healthTargetNode.parentElement, { attributes: true, attributeFilter: ['style', 'class'] });
  643. }
  644.  
  645. var ammoObserver = new MutationObserver(updateAmmoCountCopy);
  646. var ammoTargetNode = document.getElementById('ui-current-clip');
  647. if (ammoTargetNode) {
  648. ammoObserver.observe(ammoTargetNode, { attributes: true, childList: true, subtree: true });
  649. }
  650.  
  651. var weaponObserver = new MutationObserver(updateWeaponNameCopy);
  652. var weaponTargetNodes = document.querySelectorAll('.ui-weapon-switch');
  653. weaponTargetNodes.forEach(function(node) {
  654. weaponObserver.observe(node, { attributes: true, attributeFilter: ['style', 'class'] });
  655. });
  656.  
  657. var boostObserver = new MutationObserver(updateBoostWidthCopy);
  658. var boostTargetNodes = document.querySelectorAll('#ui-boost-counter .ui-bar-inner');
  659. boostTargetNodes.forEach(function(node) {
  660. boostObserver.observe(node, { attributes: true, attributeFilter: ['style', 'class'] });
  661. });
  662.  
  663. } else {
  664. var healthBarWidthCopy = document.getElementById('health-bar-width-copy');
  665. if (healthBarWidthCopy) {
  666. healthBarWidthCopy.parentNode.removeChild(healthBarWidthCopy);
  667. }
  668.  
  669. var ammoCountCopy = document.getElementById('ammo-count-copy');
  670. if (ammoCountCopy) {
  671. ammoCountCopy.parentNode.removeChild(ammoCountCopy);
  672. }
  673.  
  674. var weaponNameCopy = document.getElementById('weapon-name-copy');
  675. if (weaponNameCopy) {
  676. weaponNameCopy.parentNode.removeChild(weaponNameCopy);
  677. }
  678.  
  679. var boostWidthCopy = document.getElementById('boost-width-copy');
  680. if (boostWidthCopy) {
  681. boostWidthCopy.parentNode.removeChild(boostWidthCopy);
  682. }
  683. }
  684. }
  685.  
  686. toggleUIElementDisplay(true);
  687. showKillCounter();
  688. periodicallyShowKillCounter();
  689. })();