Show NPC Time Til Next Level at Loader

Shows the time til the next level for NPCs at the attack loader page. Uses https://api.lzpt.io/loot to get the data. Also modifies tab title, disable by modifying IF_UPDATE_TAB_TITLE to false.

目前为 2024-12-05 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Show NPC Time Til Next Level at Loader
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Shows the time til the next level for NPCs at the attack loader page. Uses https://api.lzpt.io/loot to get the data. Also modifies tab title, disable by modifying IF_UPDATE_TAB_TITLE to false.
  6. // @author Hesper [2924630]
  7. // @include https://www.torn.com/loader.php?sid=attack&user2ID=*
  8. // @grant GM.xmlHttpRequest
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // Displays time remaining until the next level in the tab title.
  16. // Set to false to disable
  17. const IF_UPDATE_TAB_TITLE = true;
  18.  
  19. const validIDs = [10, 20, 21, 4, 19, 15, 17];
  20.  
  21. // Function to fetch JSON data
  22. function fetchData() {
  23. return new Promise((resolve, reject) => {
  24. GM.xmlHttpRequest({
  25. method: 'GET',
  26. url: 'https://api.lzpt.io/loot',
  27. onload: function(response) {
  28. if (response.status >= 200 && response.status < 300) {
  29. try {
  30. const data = JSON.parse(response.responseText);
  31. resolve(data);
  32. } catch (e) {
  33. reject(e);
  34. }
  35. } else {
  36. reject(new Error(`HTTP error! status: ${response.status}`));
  37. }
  38. },
  39. onerror: function(err) {
  40. reject(err);
  41. }
  42. });
  43. });
  44. }
  45.  
  46. function calculateTimeRemaining(currentTime, hospOutTime) {
  47. const levelTimes = [0, 30, 90, 210, 450]; // Minutes after hosp_out for each level
  48. let currentLevel = 0;
  49. let timeRemaining = 0;
  50.  
  51. if (currentTime < hospOutTime) {
  52. timeRemaining = hospOutTime - currentTime;
  53. } else {
  54. for (let level = 1; level <= 5; level++) {
  55. const targetTime = hospOutTime + levelTimes[level - 1] * 60; // Convert minutes to seconds
  56. timeRemaining = targetTime - currentTime;
  57. if (timeRemaining > 0) {
  58. currentLevel = level;
  59. break;
  60. }
  61. }
  62. }
  63.  
  64. return { currentLevel, timeRemaining: timeRemaining > 0 ? timeRemaining : 0 };
  65. }
  66.  
  67. function formatTime(seconds) {
  68. const minutes = Math.floor(seconds / 60);
  69. const hours = Math.floor(minutes / 60);
  70. const remainingMinutes = minutes % 60;
  71. const remainingSeconds = seconds % 60;
  72. if (hours === 0) {
  73. if (remainingMinutes === 0) {
  74. return `${remainingSeconds}s`;
  75. }
  76. return `${remainingMinutes}m ${remainingSeconds}s`;
  77. }
  78. return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
  79. }
  80.  
  81. function updateDiv(npc, currentTime) {
  82.  
  83. const hospOutTime = npc.hosp_out;
  84. const { currentLevel, timeRemaining } = calculateTimeRemaining(currentTime, hospOutTime);
  85. let level = currentLevel;
  86.  
  87. const targetDiv = document.querySelector('.titleContainer___QrlWP');
  88. if (targetDiv) {
  89. let newDiv = document.querySelector('#npc-level-info');
  90. if (!newDiv) {
  91. newDiv = document.createElement('div');
  92. newDiv.id = 'npc-level-info';
  93. newDiv.style.marginTop = '15px';
  94. newDiv.style.marginRight = '10px';
  95. newDiv.style.textAlign = 'right';
  96. newDiv.style.fontSize = '1em';
  97. newDiv.style.lineHeight = '1.2em';
  98.  
  99. targetDiv.parentNode.insertBefore(newDiv, targetDiv.nextSibling);
  100. }
  101. if (level < 5) {
  102. newDiv.innerHTML = `Currently <b>Level ${level}</b><br />Time til Level ${level + 1}: <b>${formatTime(timeRemaining)}</b>`;
  103. if (IF_UPDATE_TAB_TITLE) document.title = `${formatTime(timeRemaining)} til Level ${level + 1} - ${npc.name}`;
  104. } else {
  105. newDiv.innerHTML = `Currently <b>Level ${level}</b>`;
  106. if (IF_UPDATE_TAB_TITLE) document.title = `Level ${level} - ${npc.name}`;
  107. }
  108. }
  109. }
  110.  
  111. async function startUpdating(user2ID) {
  112. // Check if the user2ID is valid
  113. const npcData = await fetchData();
  114. const npc = npcData.npcs[user2ID];
  115. if (!npc) return;
  116.  
  117. // Start updating the timer every second
  118. setInterval(() => {
  119. const currentTime = Math.floor(Date.now() / 1000);
  120. updateDiv(npc, currentTime);
  121. }, 1000);
  122. }
  123.  
  124. window.addEventListener('load', () => {
  125. // check if the user2ID is valid
  126. const user2ID = parseInt(new URLSearchParams(window.location.search).get('user2ID'), 10);
  127. if (validIDs.includes(user2ID)) {
  128. startUpdating(user2ID);
  129. }
  130. });
  131. })();