HWM_UnitsAssessment

Оценка силы существ в расчёте на лидерство/стоимость

  1. // ==UserScript==
  2. // @name HWM_UnitsAssessment
  3. // @namespace Небылица
  4. // @version 1.1
  5. // @description Оценка силы существ в расчёте на лидерство/стоимость
  6. // @author Небылица
  7. // @include /^https{0,1}:\/\/((www|qrator)\.heroeswm\.ru|178\.248\.235\.15)\/(army_info|leader_army)\.php/
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. "use strict";
  14.  
  15. // Настройки – вес стата
  16. const statWeight = 0.033;
  17. //
  18.  
  19. // Вспомогательные функции
  20. Number.prototype.roundTo = function(digits){ // Oкругление числа до digits знаков после запятой
  21. return Math.round(this*(10**digits))/(10**digits);
  22. }
  23. function insertAfter(newNode, referenceNode){ // Вставка newNode после referenceNode
  24. referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  25. }
  26. function assess(){ // Расчёт и вывод показателей для текущего существа
  27. var params = document.querySelectorAll(".scroll_content_half > div"),
  28. paramsNumbers = (LGArmyPage) ? [0, 2, 4, 6, 10, 11] : [0, 2, 4, 6, 7, 9], // номера нужных граф на странице ГЛ и на странице существа
  29. attack = parseInt(params[paramsNumbers[0]].innerText),
  30. defence = parseInt(params[paramsNumbers[1]].innerText),
  31. damageArr = params[paramsNumbers[2]].innerText.split("-"),
  32. damageMin = parseInt(damageArr[0]),
  33. damageMax = parseInt(damageArr[1]),
  34. damageBonus = (!LGArmyPage && GM_getValue("BFEnabled")) ? 1 : 0, // учёт урона с ББ на странице отряда при наличии соотв. настройки
  35. damageAvg = (damageMin+damageMax)/2 + damageBonus,
  36. HPBonus = (!LGArmyPage && GM_getValue("vitalityEnabled")) ? 2 : 0, // учёт ХП со стойкостью на странице отряда при наличии соотв. настройки
  37. HP = parseInt(params[paramsNumbers[3]].innerText) + HPBonus,
  38. ini = parseInt(params[paramsNumbers[4]].innerText),
  39. leadershipText = params[paramsNumbers[5]].innerText.replace(",", "") || params[paramsNumbers[5]].firstChild.value, // лидерство без и с полем ввода своей цены
  40. leadership = parseInt(leadershipText) || "?",
  41.  
  42. // 1000 – нормировочная константа для получения удобного для восприятия порядка величин
  43. damage = 1000*(damageAvg*(ini/10)*(1+statWeight*attack)),
  44. defenceWeight = (!LGArmyPage && GM_getValue("calculateWithoutDef")) ? 0 : statWeight, // расчёт без учёта дефа на странице отряда при наличии соотв. настройки
  45. vitality = 1000*(HP*(1+defenceWeight*defence)),
  46. damagePer = (damage/leadership).roundTo(2) || "?",
  47. vitalityPer = (vitality/leadership).roundTo(2) || "?",
  48. strength = Math.sqrt(damagePer*vitalityPer).roundTo(2) || "?",
  49. ECE = (100*(damage/vitality)).roundTo(2);
  50.  
  51. damagePerInnerDiv.innerText = damagePer;
  52. vitalityPerInnerDiv.innerText = vitalityPer;
  53. strengthInnerDiv.innerText = strength;
  54. ECEInnerDiv.innerText = ECE;
  55. }
  56. function setupReassessment(){ // Привязка перерасчёта параметров к смене юнита на странице ГЛ
  57. var unitNameDiv = document.getElementById("unit_name"),
  58. observer = new MutationObserver(function(mutations){
  59. mutations.forEach(function(mutation){
  60. assess();
  61. });
  62. }),
  63. config = {characterData: false, attributes: false, childList: true, subtree: false};
  64. observer.observe(unitNameDiv, config);
  65. }
  66. function setLeadershipTitle(){ // Замена "Лидерства" на "Стоимость" в зависимости от того, выбран ли ручной ввод
  67. leadershipTitle = (customPriceCheckbox.checked) ? "Стоимость" : "Лидерство";
  68. leadershipTitleNode.nodeValue = leadershipTitle;
  69. }
  70. function setupLeadershipNumberElement(){ // Отрисовывает элемент со стоимостью стека и вешает событие по изменению кастомной цены в зависимости от сохранённой настройки
  71. if (GM_getValue("customPriceEnabled")){
  72. leadershipNumber.innerHTML = "<input type='text' value='" + oldLeadership + "'>";
  73.  
  74. var leadershipNumberInput = leadershipNumber.firstChild;
  75. leadershipNumberInput.setAttribute("id", "unitsAssessmentLeadershipNumberInput");
  76.  
  77. leadershipNumberInput.style =
  78. "width: 50px;" +
  79. "height: 19px;" +
  80. "background-image: linear-gradient(rgb(166, 166, 166), rgb(163, 163, 163));" +
  81. "border: 0px;" +
  82. "text-align: right;" +
  83. "font-size: 15.6px;" +
  84. "font-weight: bold;" +
  85. "font-family: verdana, geneva, arial cyr;" +
  86. "color: #000000;";
  87.  
  88. // вешаем событие по изменению кастомной цены
  89. leadershipNumberInput.oninput = function(){
  90. if (leadershipNumberInput.value.match(/^\d+$/)){ // если лидерство – число, то считаем показатели
  91. assess();
  92. }
  93. };
  94. } else{
  95. leadershipNumber.innerHTML = oldLeadership;
  96. }
  97. }
  98. function imitateCheck(checkbox){ // Имитация нажатия на чекбокс
  99. checkbox.checked = !checkbox.checked;
  100. checkbox.dispatchEvent(changeEvent);
  101. }
  102. //
  103.  
  104.  
  105. const LGArmyPage = location.href.match("/leader_army"),
  106. emptyImageSrc = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRFAAAAp3o92gAAAAF0Uk5TAEDm2GYAAAANSURBVHicY2AYBdQEAAFQAAHr5ijJAAAAAElFTkSuQmCC";
  107.  
  108. var damagePerDiv = document.createElement("div"),
  109. vitalityPerDiv = document.createElement("div"),
  110. strengthDiv = document.createElement("div"),
  111. ECEDiv = document.createElement("div"),
  112. armyInfo = document.getElementsByClassName("info_text_content")[0];
  113.  
  114. damagePerDiv.setAttribute("class", "scroll_content_half");
  115. vitalityPerDiv.setAttribute("class", "scroll_content_half");
  116. strengthDiv.setAttribute("class", "scroll_content_half");
  117. ECEDiv.setAttribute("class", "scroll_content_half");
  118.  
  119. var rightColPaddingLeft = (LGArmyPage) ? "0.45em" : "0.3em";
  120. vitalityPerDiv.style.paddingLeft = rightColPaddingLeft;
  121. ECEDiv.style.paddingLeft = rightColPaddingLeft;
  122.  
  123. damagePerDiv.innerHTML =
  124. "<img src='" + emptyImageSrc + "' width='48' height='48'>Дамажность<div id='unitsAssessmentDamagePerInnerDiv'></div>";
  125. vitalityPerDiv.innerHTML =
  126. "<img src='" + emptyImageSrc + "' width='48' height='48'>Живучесть<div id='unitsAssessmentVitalityPerInnerDiv'></div>";
  127. strengthDiv.innerHTML =
  128. "<img src='" + emptyImageSrc + "' width='48' height='48'>Сила<div id='unitsAssessmentStrengthInnerDiv'></div>";
  129. ECEDiv.innerHTML =
  130. "<img src='" + emptyImageSrc + "' width='48' height='48'>КПД<div id='unitsAssessmentECEInnerDiv'></div>";
  131.  
  132. damagePerDiv.title =
  133. "Чем Дамажность больше, тем больше ДПС (дамага на время) приходится на единицу лидерства. " +
  134. "Учитываются урон, статы атаки и инициатива (как модификатор при расчёте ДПС, без учёта возможного эффекта от права первого удара). " +
  135. "Значение ориентировочное, абилки НЕ учитываются. Рассчитано с весом стата = " +
  136. statWeight + ". Совокупность Дамажности и Живучести составляет Силу. Отношение этих двух показателей – КПД.";
  137. vitalityPerDiv.title =
  138. "Чем Живучесть больше, тем больше мяса приходится на единицу лидерства. Учитываются здоровье и статы защиты. " +
  139. "Значение ориентировочное, абилки НЕ учитываются. Рассчитано с весом стата = " +
  140. statWeight + ". Совокупность Дамажности и Живучести составляет Силу. Отношение этих двух показателей – КПД.";
  141. strengthDiv.title =
  142. "Чем Сила больше, тем больше ДПС и мяса приходится на единицу лидерства (и тем лучше). " +
  143. "Учитываются урон, здоровье, статы атаки и защиты, инициатива (как модификатор при расчёте ДПС, без учёта возможного эффекта от права первого удара). " +
  144. "Значение ориентировочное, абилки НЕ учитываются. Рассчитано с весом стата = " +
  145. statWeight + ". Увеличение/уменьшение лидерства в n раз = синхронное уменьшение/увеличение и урона, и ХП в n раз = уменьшение/увеличение Силы в n раз. " +
  146. "При досчитывании показателя отдельно по 1 составляющей (для учёта абилок в каждом конкретном сценарии их реализации) " +
  147. "надо брать корень из модификатора разницы (урон вдвое выше – Сила в 1.41 раза выше).";
  148. ECEDiv.title =
  149. "Сколько процентов составляет урон от мяса (актуально не только для ГЛ, лидерство не влияет). " +
  150. "Чем он больше, тем больше ДПС приходится на единицу ХП (юнит более дамажный и тонкий); чем меньше – тем более мясной. " +
  151. "Могут быть оптимальны различные показатели в зависимости от стиля игры. " +
  152. "В общем случае желательна близость всех боевых юнитов в наборе по КПД (за исключением коробочной связки). " +
  153. "Рассчитано с весом стата = " + statWeight + ".";
  154.  
  155. armyInfo.appendChild(damagePerDiv);
  156. armyInfo.appendChild(vitalityPerDiv);
  157. armyInfo.appendChild(strengthDiv);
  158. armyInfo.appendChild(ECEDiv);
  159.  
  160. var damagePerInnerDiv = document.getElementById("unitsAssessmentDamagePerInnerDiv"),
  161. vitalityPerInnerDiv = document.getElementById("unitsAssessmentVitalityPerInnerDiv"),
  162. strengthInnerDiv = document.getElementById("unitsAssessmentStrengthInnerDiv"),
  163. ECEInnerDiv = document.getElementById("unitsAssessmentECEInnerDiv");
  164.  
  165. // активируем расчёт в зависимости от страницы
  166. if (LGArmyPage){
  167. setupReassessment();
  168. } else{
  169. assess();
  170.  
  171. // рисуем и вставляем чекбоксы с настройками
  172. var frameDiv = document.getElementsByClassName("army_info")[0],
  173. showArmyDiv = document.getElementById("show_army"),
  174. settingsDiv = document.createElement("div");
  175.  
  176. if (frameDiv.clientHeight < 410){frameDiv.style.height = "410px";} // растягиваем поле с параметрами при недостаточной высоте
  177.  
  178. settingsDiv.setAttribute("id", "unitsAssessmentSettingsDiv");
  179. settingsDiv.innerHTML =
  180. "<style>" +
  181. "#unitsAssessmentSettingsDiv{" +
  182. "width: 300px;" +
  183. "height: 40px;" +
  184. "margin-left: 656px;" +
  185. "font-size: 10pt;" +
  186. "font-weight: bold;" +
  187. "color: #272727;" +
  188. "}" +
  189.  
  190. "#unitsAssessmentSettingsCustomPriceSpan, #unitsAssessmentSettingsCalculateWithoutDefSpan," +
  191. "#unitsAssessmentSettingsBFSpan, #unitsAssessmentSettingsVitalitySpan{" +
  192. "display: inline-block;" +
  193. "width: 48%;" +
  194. "margin: 2px 0px 0px 4px;" +
  195. "}" +
  196.  
  197. "#unitsAssessmentSettingsCustomPriceTitle, #unitsAssessmentSettingsCalculateWithoutDefTitle," +
  198. "#unitsAssessmentSettingsBFTitle, #unitsAssessmentSettingsVitalityTitle{" +
  199. "display: inline-block;" +
  200. "width: 87%;" +
  201. "text-align: left;" +
  202. "}" +
  203.  
  204. "#unitsAssessmentSettingsCustomPriceCheckboxSpan, #unitsAssessmentSettingsCalculateWithoutDefCheckboxSpan," +
  205. "#unitsAssessmentSettingsBFCheckboxSpan, #unitsAssessmentSettingsVitalityCheckboxSpan{" +
  206. "display: inline-block;" +
  207. "width: 13%;" +
  208. "text-align: right;" +
  209. "}" +
  210. "</style>" +
  211.  
  212. "<span id='unitsAssessmentSettingsCustomPriceSpan'><span id='unitsAssessmentSettingsCustomPriceTitle'>Ручной ввод</span><span id='unitsAssessmentSettingsCustomPriceCheckboxSpan'><input type='checkbox' id='unitsAssessmentSettingsCustomPriceCheckbox'></span></span>" +
  213. "<span id='unitsAssessmentSettingsCalculateWithoutDefSpan'><span id='unitsAssessmentSettingsCalculateWithoutDefTitle'>Без учёта дефа</span><span id='unitsAssessmentSettingsCalculateWithoutDefCheckboxSpan'><input type='checkbox' id='unitsAssessmentSettingsCalculateWithoutDefCheckbox'></span></span><br>" +
  214. "<span id='unitsAssessmentSettingsBFSpan'><span id='unitsAssessmentSettingsBFTitle'>Боевое безумие</span><span id='unitsAssessmentSettingsBFCheckboxSpan'><input type='checkbox' id='unitsAssessmentSettingsBFCheckbox'></span></span>" +
  215. "<span id='unitsAssessmentSettingsVitalitySpan'><span id='unitsAssessmentSettingsVitalityTitle'>Стойкость</span><span id='unitsAssessmentSettingsVitalityCheckboxSpan'><input type='checkbox' id='unitsAssessmentSettingsVitalityCheckbox'></span></span>";
  216.  
  217. insertAfter(settingsDiv, showArmyDiv);
  218.  
  219. // задаём переменные для созданных элементов
  220. var customPriceSpan = document.getElementById("unitsAssessmentSettingsCustomPriceSpan"),
  221. calculateWithoutDefSpan = document.getElementById("unitsAssessmentSettingsCalculateWithoutDefSpan"),
  222. BFSpan = document.getElementById("unitsAssessmentSettingsBFSpan"),
  223. vitalitySpan = document.getElementById("unitsAssessmentSettingsVitalitySpan"),
  224.  
  225. customPriceTitle = document.getElementById("unitsAssessmentSettingsCustomPriceTitle"),
  226. calculateWithoutDefTitle = document.getElementById("unitsAssessmentSettingsCalculateWithoutDefTitle"),
  227. BFTitle = document.getElementById("unitsAssessmentSettingsBFTitle"),
  228. vitalityTitle = document.getElementById("unitsAssessmentSettingsVitalityTitle"),
  229.  
  230. customPriceCheckbox = document.getElementById("unitsAssessmentSettingsCustomPriceCheckbox"),
  231. calculateWithoutDefCheckbox = document.getElementById("unitsAssessmentSettingsCalculateWithoutDefCheckbox"),
  232. BFCheckbox = document.getElementById("unitsAssessmentSettingsBFCheckbox"),
  233. vitalityCheckbox = document.getElementById("unitsAssessmentSettingsVitalityCheckbox"),
  234.  
  235. RBCorner = document.querySelector(".corner_rb"); // и для уголка
  236.  
  237. customPriceSpan.title =
  238. "Ручной ввод стоимости (для сравнения юнитов по текущей цене в ивенте, а не по лидерству в рамках ГЛ).";
  239. calculateWithoutDefSpan.title =
  240. "Расчёт показателей с нулевым весом дефа (против хаоситов).";
  241. BFSpan.title =
  242. "Расчёт показателей с учётом взятия Боевого безумия.";
  243. vitalitySpan.title =
  244. "Расчёт показателей с учётом взятия Стойкости.";
  245. RBCorner.title = vitalitySpan.title;
  246.  
  247. // ставим галочки при наличии сохранённых положительных значений
  248. customPriceCheckbox.checked = GM_getValue("customPriceEnabled");
  249. calculateWithoutDefCheckbox.checked = GM_getValue("calculateWithoutDef");
  250. BFCheckbox.checked = GM_getValue("BFEnabled");
  251. vitalityCheckbox.checked = GM_getValue("vitalityEnabled");
  252.  
  253. // сохраняем реальное лидерство
  254. var leadershipDiv = armyInfo.children[9],
  255. leadershipTitleNode = leadershipDiv.firstChild.nextSibling.nextSibling,
  256. leadershipTitle,
  257. leadershipNumber = leadershipDiv.children[1],
  258. oldLeadership = leadershipNumber.innerText.replace(",", "");
  259.  
  260. // выставляем подпись лидерству, отрисовываем поле ввода цены в соответствии с сохранёнными настройками
  261. setLeadershipTitle();
  262. setupLeadershipNumberElement();
  263.  
  264. // вешаем события по изменению чекбоксов
  265. customPriceCheckbox.onchange = function(){
  266. GM_setValue("customPriceEnabled", customPriceCheckbox.checked);
  267. setLeadershipTitle();
  268. setupLeadershipNumberElement();
  269.  
  270. if (!customPriceCheckbox.checked){ // при снятии чекбокса пересчитываем показатели (уже по старому лидерству)
  271. assess();
  272. }
  273. };
  274. calculateWithoutDefCheckbox.onchange = function(){
  275. GM_setValue("calculateWithoutDef", calculateWithoutDefCheckbox.checked);
  276. assess();
  277. };
  278. BFCheckbox.onchange = function(){
  279. GM_setValue("BFEnabled", BFCheckbox.checked);
  280. assess();
  281. };
  282. vitalityCheckbox.onchange = function(){
  283. GM_setValue("vitalityEnabled", vitalityCheckbox.checked);
  284. assess();
  285. };
  286.  
  287. // имитируем нажатия на чекбоксы по клику на заголовках (для стойкости – и на НП уголке)
  288. var changeEvent = new Event("change");
  289. customPriceTitle.onclick = function(){imitateCheck(customPriceCheckbox);};
  290. calculateWithoutDefTitle.onclick = function(){imitateCheck(calculateWithoutDefCheckbox);};
  291. BFTitle.onclick = function(){imitateCheck(BFCheckbox);};
  292. vitalityTitle.onclick = function(){imitateCheck(vitalityCheckbox);};
  293. RBCorner.onclick = function(){imitateCheck(vitalityCheckbox);};
  294. }
  295. })();