Elethor Spire Build Copy

Copy your spire build

  1. // ==UserScript==
  2. // @name Elethor Spire Build Copy
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Copy your spire build
  6. // @author Eugene
  7. // @match https://elethor.com/fight/spire
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_setClipboard
  10. // @license GPL-3.0-or-later
  11. // ==/UserScript==
  12. /*
  13. * This program is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation, either version 3 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  25. */
  26. (function() {
  27. 'use strict';
  28.  
  29. let modifiers = null;
  30. let choices = null;
  31. let btn = null;
  32.  
  33. function init() {
  34. if (!window.location.href.includes('elethor.com/fight/spire')) {
  35. if (btn) btn.remove();
  36. return;
  37. }
  38.  
  39. if (document.getElementById('build-copy-btn')) return;
  40.  
  41. btn = document.createElement('button');
  42. btn.id = 'build-copy-btn';
  43. btn.innerHTML = 'Copy Build';
  44. Object.assign(btn.style, {
  45. position: 'fixed',
  46. bottom: '20px',
  47. right: '20px',
  48. zIndex: '9999',
  49. padding: '12px 16px',
  50. background: '#2563eb',
  51. color: '#fff',
  52. border: 'none',
  53. borderRadius: '6px',
  54. cursor: 'pointer',
  55. fontSize: '14px',
  56. fontWeight: '500'
  57. });
  58.  
  59. btn.addEventListener('click', handleCopy);
  60. document.body.appendChild(btn);
  61.  
  62. loadData();
  63. }
  64.  
  65. function loadData() {
  66. GM_xmlhttpRequest({
  67. method: 'GET',
  68. url: 'https://elethor.com/game/neo-spire/modifiers',
  69. onload: r => {
  70. modifiers = JSON.parse(r.responseText);
  71. tryFormat();
  72. }
  73. });
  74.  
  75. GM_xmlhttpRequest({
  76. method: 'GET',
  77. url: 'https://elethor.com/game/views/neo-spire',
  78. onload: r => {
  79. choices = JSON.parse(r.responseText);
  80. tryFormat();
  81. }
  82. });
  83. }
  84.  
  85. function tryFormat() {
  86. if (modifiers && choices && btn) {
  87. btn.disabled = false;
  88. }
  89. }
  90.  
  91. function getBuildString() {
  92. const prog = choices.progress.modifiers;
  93. const off = [];
  94. const def = [];
  95.  
  96. for (let i = 1; i <= 20; i++) {
  97. const lvl = `A${i}`;
  98.  
  99. if (prog.Offense?.[lvl]) {
  100. const pick = prog.Offense[lvl];
  101. const opts = modifiers.modifiers.Offense[lvl];
  102. const idx = opts.findIndex(m => m.id === pick.id) + 1;
  103. off.push(idx);
  104. }
  105.  
  106. if (prog.Defense?.[lvl]) {
  107. const pick = prog.Defense[lvl];
  108. const opts = modifiers.modifiers.Defense[lvl];
  109. const idx = opts.findIndex(m => m.id === pick.id) + 1;
  110. def.push(idx);
  111. }
  112. }
  113.  
  114. return `Offensive: ${off.join('-')}\nDefensive: ${def.join('-')}`;
  115. }
  116.  
  117. function handleCopy() {
  118. const build = getBuildString();
  119. GM_setClipboard(build);
  120.  
  121. const orig = btn.innerHTML;
  122. btn.innerHTML = 'Copied!';
  123. btn.style.background = '#059669';
  124.  
  125. setTimeout(() => {
  126. btn.innerHTML = orig;
  127. btn.style.background = '#2563eb';
  128. }, 1500);
  129. }
  130.  
  131. init();
  132.  
  133. let currentUrl = location.href;
  134. new MutationObserver(() => {
  135. if (location.href !== currentUrl) {
  136. currentUrl = location.href;
  137. init();
  138. }
  139. }).observe(document, {subtree: true, childList: true});
  140.  
  141. })();