home_page_helper

Открывает самую выгодную работу в секторе. Кнопка сброса статов не исчезает, + опция добавить 5 статов 1 кликом (можно спамить)

当前为 2024-11-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name home_page_helper
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.8
  5. // @description Открывает самую выгодную работу в секторе. Кнопка сброса статов не исчезает, + опция добавить 5 статов 1 кликом (можно спамить)
  6. // @license University of Ligma
  7. // @author Something begins
  8. // @match https://www.heroeswm.ru/*
  9. // @match https://my.lordswm.com/*
  10. // @match https://www.lordswm.com/*
  11. // @exclude /^https{0,1}:\/\/(www\.heroeswm\.ru|178\.248\.235\.15|my\.lordswm\.com)\/(login|war|cgame|frames|chat|chatonline|ch_box|chat_line|ticker|chatpost|chat2020|battlechat|campaign)\.php
  12. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  13. // @grant none
  14. // ==/UserScript==
  15. if (!location.pathname.includes("home.php") && !document.querySelector("#hwm_topline_with_hint2")) {
  16. throw new Error("Sorry mate, wrong door");
  17. }
  18. let i;
  19. const statAmount = 5;
  20. const facility_types = ['sh', 'fc', 'mn']
  21. const sector_coords_1 = {
  22. "Ungovernable Steppe": [48, 48],
  23. "Eagle Nest": [49, 48],
  24. "Peaceful Camp": [50, 48],
  25. "Crystal Garden": [51, 48],
  26. "Fairy Trees": [52, 48],
  27. "Mithril Coast": [53, 49],
  28. "Bear Mountain": [52, 49],
  29. "Rogues' Wood": [51, 49],
  30. "Tiger Lake": [50, 49],
  31. "Shining Spring": [49, 49],
  32. "Sunny City": [48, 49],
  33. "Sublime Arbor": [48, 50],
  34. "Green Wood": [49, 50],
  35. "Empire Capital": [50, 50],
  36. "East River": [51, 50],
  37. "Magma Mines": [52, 50],
  38. "Harbour City": [53, 50],
  39. "Lizard Lowland": [49, 51],
  40. "Wolf Dale": [50, 51],
  41. "Dragons' Caves": [51, 51],
  42. "The Wilderness": [49, 52],
  43. "Portal Ruins": [50, 52],
  44. "Great Wall": [51, 52],
  45. "Titans' Valley": [51, 53],
  46. "Fishing Village": [52, 53],
  47. "Kingdom Castle": [52, 54]
  48. }
  49. let isExecuting = false; // Tracks if the function is running
  50. const queue = []; // Queue to store pending executions
  51. const resetStatsHTML =
  52. `
  53. <div id="script_reset_stats" class="home_reset_btn btn_hover show_hint" hint="Сбросить параметры" onclick="home_css_change_stat('reset', 1, this);return false;" hwm_hint_added="1">
  54. <img src="https://dcdn2.heroeswm.ru/i/pl_info/btn_reset.png" class="inv_100mwmh">
  55. </div>
  56. `;
  57. //document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table > tbody > tr:nth-child(2) > td:nth-child(2) > table > tbody > tr:nth-child(2) > td").remove();
  58. const parser = new DOMParser();
  59. let send_get = function(url) {
  60. var xhr = new XMLHttpRequest();
  61. xhr.open('GET', url, false);
  62. xhr.overrideMimeType('text/plain; charset=windows-1251');
  63. xhr.send(null);
  64. if (xhr.status == 200) return xhr.responseText;
  65. return null;
  66. };
  67. // get element from text
  68. function getElementDepth(element) {
  69. if (!element.children || element.children.length === 0) {
  70. return 1;
  71. }
  72. let maxDepth = 0;
  73. for (let child of element.children) {
  74. let childDepth = getElementDepth(child);
  75. if (childDepth > maxDepth) {
  76. maxDepth = childDepth;
  77. }
  78. }
  79. return maxDepth + 1;
  80. }
  81.  
  82. function getLeastLayered(elArr) {
  83. const eleMap = new Map();
  84. for (const ele of elArr) {
  85. eleMap.set(ele, getElementDepth(ele));
  86. }
  87. let minKey = null;
  88. let minValue = Infinity;
  89. for (let [key, value] of eleMap.entries()) {
  90. if (value < minValue) {
  91. minValue = value;
  92. minKey = key;
  93. }
  94. }
  95. return minKey
  96. }
  97.  
  98. function findFromString(arg, eleType) {
  99. const allEles = document.querySelectorAll(eleType);
  100. let includeArr;
  101. if (typeof arg === "object") {
  102. includeArr = Array.from(allEles).filter(ele => {
  103. let othersInclude = true;
  104. for (const str of arg) {
  105. if (!ele.textContent.includes(str)) {
  106. othersInclude = false;
  107. break;
  108. }
  109. }
  110. return othersInclude;
  111. });
  112. } else {
  113. includeArr = Array.from(allEles).filter(ele => { return ele.textContent.includes(arg) });
  114. }
  115.  
  116. return getLeastLayered(includeArr);
  117. }
  118.  
  119. function processQueue() {
  120. if (isExecuting || queue.length === 0) return;
  121.  
  122. isExecuting = true;
  123. const { containerIndex, i } = queue.shift(); // Dequeue the next execution
  124. clickStat(containerIndex, i);
  125. }
  126.  
  127. function findAndGo() {
  128. let maxFacility;
  129. let maxValue = Number.NEGATIVE_INFINITY;
  130. let reponse_text = send_get(`${location.protocol}//${location.host}/map.php?`);
  131. let doc = parser.parseFromString(reponse_text, 'text/html');
  132. let cur_sector_1 = doc.querySelector("#set_mobile_max_width > div.global_container_block_header > b");
  133. if (cur_sector_1) cur_sector_1 = cur_sector_1.innerText;
  134. let cur_sector_cx = sector_coords_1[cur_sector_1][0];
  135. let cur_sector_cy = sector_coords_1[cur_sector_1][1];
  136. for (const f_type of facility_types) {
  137. let reponse_text = send_get(`${location.protocol}//${location.host}/map.php?cx=${cur_sector_cx}&cy=${cur_sector_cy}&st=${f_type}&action=get_objects&js_output=1&rand=616285.8014822785`);
  138. let doc = parser.parseFromString(reponse_text, 'text/html');
  139. let available_facilities = {};
  140. for (const el of doc.getElementsByClassName("map_obj_table_hover")) {
  141. if (el.classList.length > 1 || el.innerHTML.includes(`color="#E65054"`)) continue
  142. const facility_a = el.querySelector("td:nth-child(4) a")
  143. available_facilities[facility_a.href] = parseInt(facility_a.querySelector("b").innerText)
  144.  
  145. }
  146. if (available_facilities.length === 0) continue;
  147. for (const facility in available_facilities) {
  148. if (available_facilities[facility] > maxValue) {
  149. maxFacility = facility;
  150. maxValue = available_facilities[facility];
  151. }
  152. }
  153. if (maxFacility === undefined) continue;
  154. // break;
  155. }
  156. if (maxFacility) location.href = maxFacility;
  157. else alert("Не найдено доступных предприятий");
  158. }
  159.  
  160. function clickStat(containerIndex, i = 0) {
  161. if (i === statAmount) {
  162. isExecuting = false;
  163. processQueue(); // Process the next item in the queue
  164. return;
  165. }
  166.  
  167. const root = Array.from(document.querySelectorAll(".inv_stat_data"))[containerIndex];
  168. const button = root.querySelector(".btn_hover2");
  169. if (!button) {
  170. queue = [];
  171. return;
  172.  
  173. }
  174. const oldCount = root.querySelector(".home_stat_text").textContent;
  175.  
  176. button.click();
  177. let newCount;
  178. const changesApplied = setInterval(() => {
  179. const root = Array.from(document.querySelectorAll(".inv_stat_data"))[containerIndex];
  180. newCount = root.querySelector(".home_stat_text").textContent;
  181. if (oldCount === newCount) return;
  182.  
  183. clearInterval(changesApplied);
  184. clickStat(containerIndex, i + 1); // Continue the recursive function
  185. }, 10);
  186. }
  187.  
  188.  
  189. function insertPlus10() {
  190. const statDivs = Array.from(document.querySelectorAll(".inv_stat_data")).slice(0, 4);
  191. if (document.querySelector("div[containerIndex]") || !document.body.innerHTML.includes("Свободных очков")) return;
  192. for (const containerIndex in statDivs) {
  193. statDivs[containerIndex].insertAdjacentHTML("beforeend", `<div containerIndex=${containerIndex} class="home_button2 btn_hover2" style="display:inline-block; margin-top: 10px; width: 150%; font-size: 12">+${statAmount}</div>`);
  194. }
  195. }
  196.  
  197. function insertStatButton() {
  198. const resetButton = document.querySelector(".home_reset_btn");
  199. if (resetButton) return;
  200. document.querySelector(".inventory_stats.home_stats").insertAdjacentHTML("afterBegin", resetStatsHTML);
  201. }
  202.  
  203. function fixStatsButton() {
  204. const homeDiv = document.querySelector("#home_css_stats_wrap_div");
  205. if (!homeDiv) return;
  206. insertStatButton();
  207. insertPlus10();
  208. const observer = new MutationObserver(mutations => {
  209. mutations.forEach(mutation => {
  210. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  211. insertStatButton();
  212. insertPlus10();
  213. }
  214. });
  215. });
  216. const config = { childList: true, subtree: true };
  217. observer.observe(homeDiv, config);
  218. }
  219. if (location.pathname.includes("home.php")) {
  220. fixStatsButton();
  221. let parent = findFromString("Вы нигде не работаете", "td");
  222. if (!parent) parent = findFromString("Вы нигде не работаете", "span");
  223. parent && parent.insertAdjacentHTML('beforeend', `<button id = "fast_work" style = "display: block; color:red;">Открыть работу</button>`)
  224.  
  225. }
  226.  
  227. document.addEventListener("click", event => {
  228. if (["fast_work", "hwm_topline_with_hint2"].includes(event.target.id) || event.target.parentElement.id === "hwm_topline_with_hint2") {
  229. event.preventDefault();
  230. findAndGo();
  231. }
  232. if (!event.target.getAttribute("containerIndex")) return;
  233. const containerIndex = parseInt(event.target.getAttribute("containerIndex"));
  234. queue.push({ containerIndex, i: 0 });
  235. processQueue();
  236. })