Elethor General Purpose

Provides some general additions to Elethor

当前为 2021-01-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Elethor General Purpose
  3. // @description Provides some general additions to Elethor
  4. // @namespace https://www.elethor.com/
  5. // @version 1.0.14
  6. // @author Anders Morgan Larsen (Xortrox)
  7. // @match https://elethor.com/*
  8. // @match https://www.elethor.com/*
  9. // @run-at document-start
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. const currentUserData = {};
  15.  
  16. const moduleName = 'Elethor General Purpose';
  17. const version = '1.0.14'
  18.  
  19. const playerHealthBarElementDefinition = '.progress.is-medium.is-danger';
  20. const playerHealthBarTextElementDefinition = '.is-fight-health';
  21.  
  22. function getBattleHealthPercentage() {
  23. const playerHealth = document.querySelector(playerHealthBarElementDefinition);
  24.  
  25. if (!playerHealth) {
  26. return 0;
  27. }
  28.  
  29. return playerHealth.value / playerHealth.max * 100;
  30. }
  31.  
  32. function initializeUpdateBattleHealthPercentage() {
  33. if (window.elethorExtrasInterval) {
  34. clearInterval(window.elethorExtrasInterval);
  35. }
  36.  
  37. window.elethorExtrasInterval = setInterval(() => {
  38. const playerHealthText = document.querySelector(playerHealthBarTextElementDefinition);
  39. const healthPercentage = getBattleHealthPercentage();
  40.  
  41. if (playerHealthText && healthPercentage && !isNaN(healthPercentage)) {
  42. let percentageDisplay;
  43. if (playerHealthText.children.length === 0) {
  44. percentageDisplay = document.createElement('span');
  45.  
  46. playerHealthText.appendChild(percentageDisplay);
  47. } else {
  48. percentageDisplay = playerHealthText.children[0];
  49.  
  50. }
  51.  
  52. if (percentageDisplay) {
  53. percentageDisplay.innerText = ` (${healthPercentage.toFixed(3)}%)`;
  54. }
  55. }
  56. }, 500);
  57.  
  58.  
  59. console.log(`[${moduleName} v${version}] Battle Percentage initialized.`);
  60. }
  61.  
  62. function initializeToastKiller() {
  63. document.addEventListener('click', function(e) {
  64. if (e.target
  65. && e.target.className
  66. && e.target.className.includes
  67. && e.target.className.includes('toasted')
  68. ) {
  69. e.target.remove();
  70. }
  71. });
  72.  
  73. console.log(`[${moduleName} v${version}] Toast Killer initialized.`);
  74. }
  75.  
  76. function initializeXHRHook() {
  77. let rawSend = XMLHttpRequest.prototype.send;
  78.  
  79. XMLHttpRequest.prototype.send = function() {
  80. if (!this._hooked) {
  81. this._hooked = true;
  82.  
  83. this.addEventListener('readystatechange', function() {
  84. if (this.readyState === XMLHttpRequest.DONE) {
  85. setupHook(this);
  86. }
  87. }, false);
  88. }
  89. rawSend.apply(this, arguments);
  90. }
  91.  
  92. function setupHook(xhr) {
  93. if (window.elethorGeneralPurposeOnUserLoad) {
  94. const e = new Event('EGPXHR');
  95. e.xhr = xhr;
  96.  
  97. window.elethorGeneralPurposeOnUserLoad.dispatchEvent(e);
  98. }
  99. }
  100. window.elethorGeneralPurposeOnUserLoad = new EventTarget();
  101.  
  102. console.log(`[${moduleName} v${version}] XHR Hook initialized.`);
  103. }
  104.  
  105. function initializeUserLoadListener() {
  106. elethorGeneralPurposeOnUserLoad.addEventListener('EGPXHR', function (e) {
  107. if (e && e.xhr
  108. && e.xhr.responseURL
  109. && e.xhr.responseURL.endsWith
  110. && e.xhr.responseURL.endsWith('/game/user')
  111. ) {
  112. try {
  113. const userData = JSON.parse(e.xhr.responseText);
  114. console.log(`[${moduleName} v${version}] User Data hook:`, userData);
  115.  
  116. if (userData) {
  117. for (const key of Object.keys(userData)) {
  118. currentUserData[key] = userData[key];
  119. }
  120.  
  121. console.log(`[${moduleName} v${version}] User Data loaded:`, currentUserData);
  122. }
  123. } catch (e) {
  124. console.log(`[${moduleName} v${version}] Error parsing userData:`, e);
  125. }
  126.  
  127. }
  128. });
  129.  
  130. console.log(`[${moduleName} v${version}] User Load Listener initialized.`);
  131. }
  132.  
  133. function initializeInventoryStatsLoadListener() {
  134. elethorGeneralPurposeOnUserLoad.addEventListener('EGPXHR', function (e) {
  135. if (e && e.xhr
  136. && e.xhr.responseURL
  137. && e.xhr.responseURL.endsWith
  138. && e.xhr.responseURL.endsWith('/game/inventory/stats')
  139. ) {
  140. setTimeout(() => {
  141. updateEquipmentPercentageSummary();
  142.  
  143. setTimeout(updateInventoryStatsPercentages, 1000);
  144. });
  145. }
  146. });
  147.  
  148. console.log(`[${moduleName} v${version}] User Load Listener initialized.`);
  149. }
  150.  
  151. function updateEquipmentPercentageSummary() {
  152. document.querySelector('.is-equipment>div>div').setAttribute('style', 'width: 50%')
  153. let percentagesTable = document.querySelector('#egpPercentagesSummary')
  154. if (!percentagesTable){
  155. percentagesTable = document.querySelector('.is-equipment>div>div:nth-child(2)').cloneNode(true);
  156. percentagesTable.setAttribute('style', 'width: 25%');
  157. percentagesTable.id='egpPercentagesSummary';
  158. document.querySelector('.is-equipment>div').appendChild(percentagesTable);
  159.  
  160. for (const child of percentagesTable.children[0].children) {
  161. child.children[0].remove();
  162. }
  163.  
  164. document.querySelector('#egpPercentagesSummary>table>tr:nth-child(8)').setAttribute('style', 'height:43px');
  165. }
  166. }
  167.  
  168. function getStatSummary(equipment) {
  169. const summary = {
  170. base: {},
  171. energizements: {}
  172. };
  173.  
  174. if (equipment) {
  175. for (const key of Object.keys(equipment)) {
  176. const item = equipment[key];
  177.  
  178. /**
  179. * Sums base attributes by name
  180. * */
  181. if (item && item.attributes) {
  182. for (const attributeName of Object.keys(item.attributes)) {
  183. const attributeValue = item.attributes[attributeName];
  184.  
  185. if (!summary.base[attributeName]) {
  186. summary.base[attributeName] = 0;
  187. }
  188.  
  189. summary.base[attributeName] += attributeValue;
  190. }
  191. }
  192.  
  193. /**
  194. * Sums energizements by stat name
  195. * */
  196. if (item && item.upgrade && item.upgrade.energizements) {
  197. for (const energizement of item.upgrade.energizements) {
  198. if (!summary.energizements[energizement.stat]) {
  199. summary.energizements[energizement.stat] = 0;
  200. }
  201.  
  202. summary.energizements[energizement.stat] += Number(energizement.boost);
  203. }
  204. }
  205. }
  206. }
  207.  
  208. return summary;
  209. }
  210.  
  211. function updateInventoryStatsPercentages() {
  212. let percentagesTable = document.querySelector('#egpPercentagesSummary')
  213. if (percentagesTable && currentUserData && currentUserData.equipment){
  214. const statSummary = getStatSummary(currentUserData.equipment);
  215.  
  216. console.log('statSummary:', statSummary);
  217.  
  218. const baseKeys = Object.keys(statSummary.base);
  219. const energizementKeys = Object.keys(statSummary.energizements);
  220.  
  221. let allKeys = baseKeys.concat(energizementKeys);
  222. const filterUniques = {};
  223. for (const key of allKeys){
  224. filterUniques[key] = true;
  225. }
  226. allKeys = Object.keys(filterUniques);
  227. allKeys.sort();
  228.  
  229. const tableRows = percentagesTable.children[0].children;
  230. let rowIndex = 0;
  231. for (const key of allKeys) {
  232. const row = tableRows[rowIndex];
  233. const rowText = row.children[0].children[0];
  234.  
  235. const rowBase = statSummary.base[key] || 0;
  236. const rowEnergizement = (statSummary.energizements[key] || 0) * 100;
  237.  
  238. if (key.startsWith('+')) {
  239. rowText.innerText = `${key}: ${rowBase} x (level/10)`;
  240. } else {
  241. rowText.innerText = `${key}: ${rowBase} (${rowEnergizement.toFixed(0)}%)`;
  242. }
  243.  
  244. rowIndex++;
  245. }
  246. }
  247. }
  248.  
  249. (function run() {
  250. initializeUpdateBattleHealthPercentage();
  251. initializeToastKiller();
  252. initializeXHRHook();
  253. initializeUserLoadListener();
  254. initializeInventoryStatsLoadListener();
  255.  
  256. console.log(`[${moduleName} v${version}] Loaded.`);
  257. })();
  258. })();
  259.