battle_damage_tooltip

Скрины с функционалом ниже. 1.) Показывает урон всех стеков одной стороны по одному выбранному стеку второй стороны. 2.) Если навести курсор на 1 существо, нажать 'e' (русская 'у'), сделать то же самое со вторым, то в чате появится урон первого по второму. Доп. настройки в настройках боя.

目前为 2023-05-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name battle_damage_tooltip
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.9.9
  5. // @description Скрины с функционалом ниже. 1.) Показывает урон всех стеков одной стороны по одному выбранному стеку второй стороны. 2.) Если навести курсор на 1 существо, нажать 'e' (русская 'у'), сделать то же самое со вторым, то в чате появится урон первого по второму. Доп. настройки в настройках боя.
  6. // @author Something begins
  7. // @license None
  8. // @match https://www.heroeswm.ru/war*
  9. // @match https://my.lordswm.com/war*
  10. // @match https://www.lordswm.com/war*
  11. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // @grant unsafeWindow
  15. // ==/UserScript==
  16. // Странные способы в некоторых местах обусловлены конфликтом со скриптом battleHelper от omne
  17. let outer_chat = document.getElementById("chat_format");
  18. outer_chat.insertAdjacentHTML("beforeend", `
  19. <div id="cre_distance_div" style="display: none"></div>
  20. <div id="individual_calc"></div>
  21. <div id="dmg_list_container"></div>
  22. <br>
  23. <button id="dmg_list_refresh" style="background-color: #3d3d29; color: white; padding: 5px 10px; border: none; border-radius: 4px; font-size: 10px; cursor: pointer">Открыть</button>
  24. <select style="display : none; background-color: #333; color: white; margin: 10px" id="choose_cre"></select>
  25. <button id="change_side" style="background-color: #6b6b47; color: white; padding: 5px 10px; border: none; border-radius: 4px; font-size: 10px; cursor: pointer; display: none">Сменить сторону</button>
  26. <button id="collapse" style="background-color: #000000; color: white; padding: 5px 10px; border: none; border-radius: 4px; font-size: 10px; cursor: pointer; display: none; margin:10px">Свернуть</button> `)
  27. let calc_x, calc_y;
  28. let last_individual_calc = {}
  29. let isOpen = false
  30. let ini_weight = 10;
  31. let chosen = {side: 1, creature: "Высшие вампиры", afterSideSwitchCre: {"-1": "", "1": ""}}
  32. let chat = document.getElementById("chat_inside");
  33. let select = document.getElementById("choose_cre")
  34. let refresh_button = document.getElementById("dmg_list_refresh")
  35. let side_button = document.getElementById("change_side")
  36. let collapse_button = document.getElementById("collapse")
  37. let individual_calc = document.querySelector("#individual_calc")
  38. let cre_distance_div = document.querySelector("#cre_distance_div")
  39. const settings_panel = document.querySelector("#webgl_settings_whole")
  40. let dmg_list_container = document.querySelector("#dmg_list_container")
  41. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  42.  
  43. // ========= utils ============
  44. function get_GM_value_if_exists(GM_key, default_value){
  45. const GM_value = GM_getValue(GM_key)
  46. return GM_value!=undefined ? GM_value : default_value;
  47. }
  48. function individual_calc_innerHTML(atk_obj_index, def_obj_index){
  49. if (atk_obj_index === undefined || def_obj_index === undefined) return ""
  50. let cre_collection = unsafeWindow.stage.pole.obj
  51. let attacker = cre_collection[atk_obj_index];
  52. let defender = cre_collection[def_obj_index];
  53. let dmg = get_dmg_info(atk_obj_index, def_obj_index)
  54. last_individual_calc.atk_obj_index = atk_obj_index; last_individual_calc.def_obj_index = def_obj_index;
  55. individual_calc.style.backgroundColor = "#000066"
  56. return ` <div id="individual_cre_heading" style="display:inline; background-color: #000066">
  57. <span>Урон <br>
  58. </span>
  59. <span>
  60. <b>${attacker.nametxt}</b> [${attacker.nownumber}] по <b>${defender.nametxt}</b> [${defender.nownumber}]: <br>
  61. <br>
  62. </span>
  63. </div>
  64. <p id="${0}" style=" background-color: #000066">
  65. <span style=color:#bfbfbf"></span>
  66. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${dmg.min_killed}-${dmg.max_killed}</b> существ ( <span style="color:#ffffff">${dmg.min}-${dmg.max}</span>)
  67. </p>
  68. <br>`
  69. }
  70. function paint_coords(x,y, color){
  71. let tile = shado[x + y*defxn]
  72. if (tile == undefined) return
  73. tile.stroke(color)
  74. tile.fill(color)
  75. set_visible(tile,1)
  76.  
  77. setTimeout(()=>{
  78. tile.fill(null)
  79. tile.stroke(null)
  80. set_visible(tile,0)
  81. },2077)
  82. }
  83. const observer = new MutationObserver((mutationsList, observer) => {
  84. for(const mutation of mutationsList) {
  85. if (mutation.type === 'childList') {
  86. for (const addedNode of mutation.addedNodes) {
  87. if (addedNode.classList && addedNode.classList.contains('cont') || ["B", "BR"].includes(addedNode.tagName)) {
  88. battleHelper_display(battleHelper_on)
  89. }
  90. }
  91. }
  92. }
  93. });
  94.  
  95. function GM_toggle_boolean(GM_key, boolean){
  96. boolean = !boolean
  97. GM_setValue(GM_key, boolean);
  98. return boolean
  99. }
  100. function set_Display(element_arr, displayProperty){
  101. element_arr.forEach(element=>{
  102. if (element == null) return
  103. element.style.display = displayProperty
  104. })
  105. }
  106. function readjust_elements(){
  107. chat = document.getElementById("chat_inside");
  108. select = document.getElementById("choose_cre")
  109. refresh_button = document.getElementById("dmg_list_refresh")
  110. side_button = document.getElementById("change_side")
  111. collapse_button = document.getElementById("collapse")
  112. dmg_list_container = document.querySelector("#dmg_list_container")
  113. individual_calc = document.querySelector("#individual_calc")
  114. cre_distance_div = document.querySelector("#cre_distance_div")
  115. }
  116. // -----------------------------------
  117. // ========= Настройки ============
  118.  
  119. let cre_distance = get_GM_value_if_exists('cre_distance', "")
  120. let cre_distance_on = get_GM_value_if_exists('cre_distance_on', false)
  121. let coeff_on = get_GM_value_if_exists('GM_coeff_on', false)
  122. let battleHelper_on = get_GM_value_if_exists('battleHelper_on', true)
  123. const new_settings = `
  124. <style>
  125. .tooltip {
  126. position: relative;
  127. display: inline-block;
  128. text-size: 150%;
  129. color: brown;
  130. text-decoration: underline;
  131. }
  132.  
  133. .tooltip .tooltiptext {
  134. visibility: hidden;
  135. position: absolute;
  136. bottom: 100%;
  137. left: 50%;
  138. width: 5000%;
  139. transform: translateX(-30%);
  140. padding: 5px;
  141. background-color: #555;
  142. color: #fff;
  143. border-radius: 6px;
  144. word-wrap: break-word;
  145. }
  146.  
  147. .tooltip:hover .tooltiptext {
  148. visibility: visible;
  149. }
  150. </style>
  151. <div class="info_row">
  152. <label class="checkbox_container">коэф. урона <span class="tooltip">? <span class="tooltiptext">отношение урон/хп (т.е. у кого больше всех коэф., с того выгоднее начинать. <br>Работает в списке уронов если нажать на "Открыть" в чате)</span>
  153. </span>
  154. <input type="checkbox" checked="true" id="coeff_on">
  155. <span class="checkbox_checkmark"></span>
  156. </label>
  157. </div>
  158. <div class="info_row">
  159. <label class="checkbox_container">battleHelper в чате <span class="tooltip">? <span class="tooltiptext">выключает или включает начальное распределение АТБ шкалы от omne</span>
  160. </span> <input type="checkbox" checked="true" id="battleHelper_on">
  161. <span class="checkbox_checkmark"></span>
  162. </label>
  163. </div>
  164. <div class="info_row">
  165. <label class="checkbox_container">Расстояние между стеками <span class="tooltip">? <span class="tooltiptext">Расстояние между атакующим и защищающимся стеками. Выбирать расстояние стрелочками в текстовом поле снизу. <br>
  166. Влияет на статус урона стрелка (ближний/дальний урон, кривая/прямая стрела),
  167. разбег и прочие абилки, зависящие от расстояния. <br> Если выставить "Расстояние: 1", то стрелок будет считаться заблокированным.
  168. Если выставить расстояние больше 1,
  169. то стрелок будет считаться не заблокированным (даже если рядом с ним вражеское существо). </span>
  170. </span>
  171. <input type="checkbox" checked="true" id="cre_distance_on">
  172. <span class="checkbox_checkmark"></span>
  173. </label>
  174. <input type="number" style="width: 4%; margin: 2px 2px 2px 80px" id="cre_distance" onkeydown="return false;" value=${cre_distance}>
  175. </div>
  176. `
  177. settings_panel.insertAdjacentHTML("beforeend", new_settings)
  178.  
  179. let settings_interval = setInterval(()=>{
  180. let temp = document.querySelector("#coeff_on")
  181. if (temp){
  182. document.querySelector("#coeff_on").checked = coeff_on
  183. document.querySelector("#battleHelper_on").checked = battleHelper_on
  184. document.querySelector("#cre_distance_on").checked = cre_distance_on
  185. clearInterval(settings_interval)
  186. }
  187. },300)
  188. const distance_counter = document.getElementById("cre_distance");
  189. distance_counter.addEventListener("input", () => {
  190. if (distance_counter.value < 1) {
  191. distance_counter.value = 1
  192. return
  193. }
  194. if (!cre_distance_on) return
  195. GM_setValue('cre_distance', distance_counter.value)
  196. if (isOpen) refresh()
  197. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  198. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  199. });
  200. document.body.addEventListener('change', function(event) {
  201. switch (event.target.id){
  202. case "coeff_on":
  203. coeff_on = GM_toggle_boolean("coeff_on", coeff_on)
  204. if (isOpen) refresh()
  205. break;
  206. case "battleHelper_on":
  207. battleHelper_on = GM_toggle_boolean("battleHelper_on", battleHelper_on)
  208. battleHelper_display(battleHelper_on)
  209. break
  210. case "choose_cre":
  211. chosen.creature = select.value
  212. refresh()
  213. break;
  214. case "cre_distance_on":
  215. cre_distance_on = GM_toggle_boolean("cre_distance_on", cre_distance_on)
  216. cre_distance_on ? GM_setValue('cre_distance', distance_counter.value): GM_setValue('cre_distance', "")
  217. if (cre_distance_on){
  218. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  219. cre_distance_div.style.display = "inline"
  220. if (isOpen) refresh()
  221. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  222. }
  223. else{
  224. cre_distance_div.innerHTML = ""
  225. }
  226. if (isOpen) refresh()
  227. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  228. break;
  229. }
  230. });
  231. // -----------------------------------
  232.  
  233. // ========= battleHelper ============
  234.  
  235. function battleHelper_display(ifDisplay){
  236. [...outer_chat.children].forEach(child=>{
  237. if (["B","BR"].includes(child.tagName) || child.className == "cont"){
  238. child.style.display = ifDisplay ? "inline" : "none"
  239. }
  240. })
  241. if (ifDisplay){
  242. if (!outer_chat.innerText.includes("Команда №1")) {
  243. let br_list = [...outer_chat.children].filter(br_element =>"BR" == br_element.tagName);
  244. let team_no = 0
  245. br_list.forEach(br_element=>{
  246. let index = br_list.indexOf(br_element)
  247. if (index%2==0 && index != br_list.length-2){
  248. team_no++;
  249. br_element.insertAdjacentHTML("afterend", `Команда ${team_no}`)
  250. }
  251. });
  252. }
  253. }
  254. else {
  255. const childNodes = outer_chat.childNodes;
  256. for (let i = 0; i < childNodes.length; i++) {
  257. const childNode = childNodes[i];
  258. if (childNode.nodeType === Node.TEXT_NODE) {
  259. const text = childNode.textContent.trim();
  260. if (text !== '') {
  261. childNode.textContent = '';
  262. }
  263. }
  264. }
  265. }
  266. }
  267. observer.observe(outer_chat, { childList: true });
  268. setTimeout(function() {
  269. observer.disconnect();
  270. }, 30000);
  271.  
  272. // -----------------------------------
  273.  
  274.  
  275. document.body.addEventListener('click', function(event) {
  276. switch(event.target.id){
  277. case "dmg_list_refresh":
  278. readjust_elements()
  279. refresh()
  280. break
  281. case "change_side":
  282. chosen.afterSideSwitchCre[chosen.side] = chosen.creature
  283. chosen.side = - chosen.side
  284. chosen.creature = chosen.afterSideSwitchCre[chosen.side]
  285. refresh()
  286. break
  287. case "collapse":
  288. readjust_elements()
  289. isOpen = false
  290. battleHelper_display(battleHelper_on);
  291. refresh_button.innerHTML = "Открыть";
  292. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc, cre_distance_div], "none")
  293. break
  294. case "confirm_ins_img":
  295. observer.observe(outer_chat, { childList: true });
  296. setTimeout(function() {
  297. observer.disconnect();
  298. }, 190000);
  299. }
  300. })
  301. outer_chat.addEventListener('change', function() {
  302. chosen.creature = select.value
  303. refresh()
  304. });
  305.  
  306. // Урон одного стека по другому по выбору нажатием кнопки E
  307. window.addEventListener("keyup", event => {
  308. if ((document.querySelector("#chattext") !== document.activeElement) && (document.querySelector("#chattext_classic") !== document.activeElement)) {
  309. if (["e", "E", "у", "У"].includes(event.key)) {
  310. let cre_collection = unsafeWindow.stage.pole.obj
  311. if (mapobj[xr_last+yr_last*defxn] === undefined || cre_collection[mapobj[xr_last+yr_last*defxn]].rock === 1) {
  312. paint_coords(xr_last,yr_last,"#cccccc")
  313. return
  314. }
  315. if (!calc_x){
  316. calc_x = xr_last
  317. calc_y = yr_last
  318. paint_coords(xr_last,yr_last,"#800000")
  319. }
  320. else {
  321. readjust_elements()
  322. let atk_obj_index = unsafeWindow.mapobj[calc_x+calc_y*defxn]
  323. let def_obj_index = unsafeWindow.mapobj[xr_last+yr_last*defxn]
  324. set_Display([individual_calc, collapse_button], "inline")
  325. if (cre_distance_on) {
  326. cre_distance_div.style.display = "inline";
  327. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  328. }
  329. individual_calc.innerHTML = individual_calc_innerHTML(atk_obj_index, def_obj_index)
  330. calc_x = calc_y = null
  331. paint_coords(xr_last,yr_last,"blue")
  332. }
  333. }
  334. }
  335. })
  336.  
  337.  
  338. // Родная функция гвд с поправками на переменную l и модификаторами magic[]
  339. function attackmonster(attacker, ax, ay, x, y, defender,cre_distance, shootok, koef, inuse) {
  340. let cre_collection = unsafeWindow.stage.pole.obj
  341. var mainattack = 1;
  342. var ax1 = ax;
  343. var ay1 = ay;
  344. if (defender == 1000) return 0;
  345. if (defender <= 0) return 0;
  346. if (!cre_collection[defender]) return 0;
  347. if (cre_collection[defender]['hero']) return 0;
  348. if (cre_collection[defender]['rock']) return 0;
  349. if (koef == undefined) koef = 1;
  350. if (inuse == undefined) inuse = '';
  351. var len = unsafeWindow.wmap2[y * defxn + x];
  352. if ((cre_collection[attacker].x == x) && (cre_collection[attacker].y == y)) len = spd;
  353. shootok = 1;
  354. function getAdjacentAndDiagonalCoords(x, y) {
  355. const adjacentAndDiagonalCoords = [];
  356. adjacentAndDiagonalCoords.push([x + 1, y]);
  357. adjacentAndDiagonalCoords.push([x - 1, y]);
  358. adjacentAndDiagonalCoords.push([x, y + 1]);
  359. adjacentAndDiagonalCoords.push([x, y - 1]);
  360. adjacentAndDiagonalCoords.push([x + 1, y + 1]);
  361. adjacentAndDiagonalCoords.push([x - 1, y + 1]);
  362. adjacentAndDiagonalCoords.push([x + 1, y - 1]);
  363. adjacentAndDiagonalCoords.push([x - 1, y - 1]);
  364. return adjacentAndDiagonalCoords;
  365. }
  366. let attacker_adjacent_coords = getAdjacentAndDiagonalCoords(stage.pole.obj[attacker].x, stage.pole.obj[attacker].y)
  367. let enemies_list = Object.values(stage.pole.obj).filter(creature=>creature.side!=stage.pole.obj[attacker].side)
  368. enemies_list.forEach(enemy=>{
  369. attacker_adjacent_coords.forEach(coord=>{
  370. if (coord[0] == enemy.x && coord[1] == enemy.y) shootok = 0
  371. })
  372. })
  373.  
  374. if (cre_collection[attacker]['big']) {
  375. if (ax > x) {
  376. x++;
  377. };
  378. if (ay > y) {
  379. y++;
  380. };
  381. };
  382. if (cre_collection[attacker]['bigx']) {
  383. if (ax > x) {
  384. x++;
  385. };
  386. };
  387. if (cre_collection[attacker]['bigy']) {
  388. if (ay > y) {
  389. y++;
  390. };
  391. };
  392. var spd = Math.max(0, Math.round((cre_collection[attacker].speed + cre_collection[attacker]['ragespeed'] + cre_collection[attacker]['speedaddon']) * cre_collection[attacker].speedmodifier));
  393. if (unsafeWindow.magic[attacker]['ent']) {
  394. spd = 0;
  395. };
  396. var movelen = spd - len;
  397. unsafeWindow.attacker_c = attacker;
  398. unsafeWindow.ax_c = ax;
  399. unsafeWindow.ay_c = ay;
  400. unsafeWindow.x_c = x;
  401. unsafeWindow.y_c = y;
  402. unsafeWindow.defender_c = defender;
  403. unsafeWindow.shootok_c = shootok;
  404. if ((x == 0) && (y == 0)) {
  405. x = cre_collection[attacker]['x'];
  406. y = cre_collection[attacker]['y'];
  407. };
  408. if ((defender > 0) && (cre_collection[defender]['big'])) {
  409. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  410. ax++;
  411. };
  412. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  413. ay++;
  414. };
  415. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  416. ax--;
  417. };
  418. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  419. ay--;
  420. };
  421. };
  422. if ((defender > 0) && (cre_collection[defender]['bigx'])) {
  423. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  424. ax++;
  425. };
  426. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  427. ax--;
  428. };
  429. };
  430. if ((defender > 0) && (cre_collection[defender]['bigy'])) {
  431. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  432. ay++;
  433. };
  434. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  435. ay--;
  436. };
  437. };
  438. let dx = x - ax;
  439. let dy = y - ay;
  440. l = dx * dx + dy * dy;
  441. if (movelen == undefined) movelen = 0;
  442. if (cre_distance !=="") {
  443. movelen = cre_distance
  444. l = Math.round(cre_distance * cre_distance)
  445. if (l > 2) shootok = 1
  446. else shootok = 0
  447. }
  448. unsafeWindow.PhysicalModifiers = 1;
  449. unsafeWindow.PhysicalModifiers *= koef;
  450. if (cre_collection[attacker]['shadowattack']) l = 0;
  451.  
  452. var hera = 0;
  453. var herd = 0;
  454. len = unsafeWindow.stage.pole.obj_array.length;
  455. for (var k1 = 0; k1 < len; k1++) {
  456. unsafeWindow.k = unsafeWindow.stage.pole.obj_array[k1];
  457.  
  458. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[attacker].owner)) hera = unsafeWindow.k;
  459. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[defender].owner)) herd = unsafeWindow.k;
  460. };
  461. if ((cre_collection[defender]['pirate']) && ((unsafeWindow.magic[defender]['sea']) || (unsafeWindow.gtype == 125) || (unsafeWindow.gtype == 126) || (unsafeWindow.gtype == 133))) {
  462. unsafeWindow.PhysicalModifiers *= 0.85;
  463. };
  464. if (cre_collection[defender]['deadflesh']) {
  465. unsafeWindow.PhysicalModifiers *= 0.8;
  466. };
  467. if (cre_collection[defender]['immaterial']) {
  468. unsafeWindow.PhysicalModifiers *= 0.65;
  469. };
  470. if ((cre_collection[attacker]['oppressionofweak']) && (cre_collection[defender]['level'] == 1)) {
  471. unsafeWindow.PhysicalModifiers *= 1.5;
  472. };
  473. if ((cre_collection[attacker]['fearofstrong']) && (cre_collection[defender]['level'] == 7)) {
  474. unsafeWindow.PhysicalModifiers *= 0.5;
  475. };
  476. if ((hera > 0) && (unsafeWindow.magic[hera]['bna'])) {
  477. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[hera]['bna']['effect'] / 100);
  478. if ((cre_collection[defender]['mechanical']) && (unsafeWindow.magic[hera]['MEC'])) {
  479. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['MEC']['effect'] / 100;
  480. };
  481. if ((cre_collection[attacker]['mechanical']) && (unsafeWindow.magic[hera]['mch'])) {
  482. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['mch']['effect'] / 100;
  483. };
  484. };
  485. if ((cre_collection[defender]['building']) && (!cre_collection[attacker]['siegewalls'])) {
  486. unsafeWindow.PhysicalModifiers *= 0.05;
  487. };
  488. if ((defender > 0) && (cre_collection[attacker]['cruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  489. unsafeWindow.PhysicalModifiers *= 1.15;
  490. };
  491. if ((defender > 0) && (cre_collection[attacker]['morecruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  492. unsafeWindow.PhysicalModifiers *= 1.3;
  493. };
  494. if ((cre_collection[attacker]['giantkiller']) && (cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 2;
  495. if ((cre_collection[attacker]['pygmykiller']) && (!cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 1.33;
  496. if (cre_collection[attacker]['stormstrike']) unsafeWindow.PhysicalModifiers *= 2;
  497. if ((cre_collection[attacker]['undeadkiller']) && (cre_collection[defender]['undead'])) unsafeWindow.PhysicalModifiers *= 1.5;
  498. if ((cre_collection[attacker]['pirate']) && (unsafeWindow.magic[defender]['blb'])) unsafeWindow.PhysicalModifiers *= 1.5;
  499. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.magic[attacker]['zat'])) {
  500. unsafeWindow.PhysicalModifiers *= 1.15;
  501. };
  502. if ((herd > 0) && (unsafeWindow.magic[herd]['bnd'])) {
  503. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers / (1 + unsafeWindow.magic[herd]['bnd']['effect'] / 100);
  504. };
  505. if ((herd > 0) && (unsafeWindow.magic[herd]['fld'])) {
  506. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[herd]['fld']['effect'] / 100);
  507. };
  508. if ((herd > 0) && (unsafeWindow.magic[herd]['rcd']) && (monster_race[cre_collection[attacker]['id']] == unsafeWindow.magic[herd]['rcd']['effect'])) {
  509. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.93;
  510. };
  511. if (unsafeWindow.magic[attacker]['prp']) {
  512. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[attacker]['prp']['effect'] / 100);
  513. };
  514. if (unsafeWindow.magic[defender]['sta']) {
  515. unsafeWindow.PhysicalModifiers *= 0.5;
  516. };
  517. if ((unsafeWindow.magic[attacker]['chd']) && (cre_collection[unsafeWindow.magic[attacker]['chd']['effect']]['nownumber'] > 0) && (unsafeWindow.magic[attacker]['chd']['effect'] != defender)) {
  518. unsafeWindow.PhysicalModifiers *= 0.55;
  519. };
  520. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.checkmembrane(defender);
  521. if (!cre_collection[attacker]['hero']) {
  522. if ((l <= 2) && (cre_collection[attacker]['shooter']) && (!cre_collection[attacker]['nopenalty']) && (!cre_collection[attacker]['warmachine'])) {
  523. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  524. };
  525. if ((l > 2) && (cre_collection[attacker]['rangepenalty'])) {
  526. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  527. };
  528. unsafeWindow.rangemod = 1;
  529. if ((l > 2) && (cre_collection[attacker]['shooter']) && (((cre_collection[attacker]['range'] < Math.sqrt(l)) && (!cre_collection[attacker].shadowattack)) || ((iswalls) && (!cre_collection[attacker]['hero']) && (unsafeWindow.checkwall(x, y, ax, ay))))) {
  530. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  531. unsafeWindow.rangemod = 0.5;
  532. };
  533. if ((l > 2) && (cre_collection[attacker]['shooter']) && (iswalls2) && (!cre_collection[attacker]['hero']) && (((!cre_collection[attacker].siegewalls) || (btype == 118)) || (!cre_collection[defender].stone)) && (unsafeWindow.checkwall2(x, y, ax, ay, attacker))) {
  534. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  535. unsafeWindow.rangemod *= 0.5;
  536. };
  537. };
  538. var _PERK_ARCHERY = 11;
  539. var _PERK_EVASION = 22;
  540. if ((defender > 0) && (cre_collection[defender]['dodge']) && (((l <= 2) && (!cre_collection[attacker]['ballista']) && (inuse != 'ssh') && (inuse != 'mga') && (inuse != 'dcd') && (inuse != 'chs') && (!cre_collection[attacker]['hero'])) || (inuse == 'brs') || (inuse == 'cpt'))) {
  541. unsafeWindow.PhysicalModifiers *= 0.5;
  542. };
  543. if ((shootok == 1) && (!cre_collection[attacker]['hero']) && (cre_collection[attacker]['shooter'])) {
  544. if (unsafeWindow.isperk(attacker, _PERK_ARCHERY)) unsafeWindow.PhysicalModifiers *= 1.2;
  545. if (unsafeWindow.isperk(defender, _PERK_EVASION)) unsafeWindow.PhysicalModifiers *= 0.8;
  546. if ((!cre_collection[defender]['lshield']) && (unsafeWindow.stage.pole.shieldother(defender))) {
  547. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  548. };
  549. if ((cre_collection[defender]['lshield']) || (cre_collection[defender]['hollowbones'])) {
  550. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  551. };
  552. if (cre_collection[defender]['diamondarmor']) {
  553. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.1;
  554. };
  555. if (cre_collection[defender]['shielded']) {
  556. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  557. };
  558. if (cre_collection[defender]['unprotectedtarget']) {
  559. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 1.25;
  560. };
  561. if (unsafeWindow.magic[defender]['dfm']) {
  562. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[defender]['dfm']['effect'] / 100);
  563. };
  564. if (unsafeWindow.magic[attacker]['cnf']) {
  565. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[attacker]['cnf']['effect'] / 100);
  566. };
  567.  
  568. if (hera > 0) {
  569. if (unsafeWindow.magic[hera]['sat']) {
  570. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[hera]['sat']['effect']) / 100;
  571. };
  572. };
  573. };
  574. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_BLESS))) {
  575. unsafeWindow.PhysicalModifiers *= 1.04;
  576. };
  577. let o = cre_collection[attacker]['owner'];
  578. if (unsafeWindow.magic[defender]['mf' + o]) {
  579. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[defender]['mf' + o]['effect'] / 100;
  580. };
  581. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_FERVOR))) {
  582. unsafeWindow.PhysicalModifiers *= 1.03;
  583. };
  584. if (hera > 0) {
  585. var h = hera;
  586. if ((unsafeWindow.magic[h]['nut']) && ((plid2 == -2) || (ohotnik_set_neutral()))) {
  587. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['nut']['effect']) / 100;
  588. };
  589. if ((unsafeWindow.magic[h]['mle']) && ((cre_collection[attacker].shooter && shootok==0)||(cre_collection[attacker].shooter!= 1) || cre_collection[attacker].shots==0)) {
  590. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['mle']['effect']) / 100;
  591. };
  592. if (unsafeWindow.magic[attacker]['fbd']) {
  593. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + Math.floor(unsafeWindow.magic[attacker]['fbd']['effect'] / 10)) / 100;
  594. };
  595. };
  596. unsafeWindow.monatt = cre_collection[attacker]['attack'] + cre_collection[attacker]['attackaddon'] + cre_collection[attacker]['rageattack'];
  597. if ((defender > 0) && (cre_collection[attacker]['giantslayer']) && (cre_collection[defender]['big'])) unsafeWindow.monatt += 4;
  598. if ((!cre_collection[attacker]['undead']) && (!cre_collection[attacker]['hero']) && (!cre_collection[attacker]['perseverance'])) {
  599. unsafeWindow.frig2 = false;
  600. unsafeWindow.i = attacker;
  601. var bigx = cre_collection[i]['big'];
  602. var bigy = cre_collection[i]['big'];
  603. if (cre_collection[i]['bigx']) bigx = 1;
  604. if (cre_collection[i]['bigy']) bigy = 1;
  605. unsafeWindow.xd = cre_collection[i]['x'];
  606. unsafeWindow.yd = cre_collection[i]['y'];
  607. for (var xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  608. for (var yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  609. if ((!unsafeWindow.frig2) && (mapobj[yz * defxn + xz] > 0) && (cre_collection[mapobj[yz * defxn + xz]]['side'] != cre_collection[i]['side']) && (cre_collection[mapobj[yz * defxn + xz]]['festeringaura']) && (cre_collection[mapobj[yz * defxn + xz]]['nownumber'] > 0)) {
  610. unsafeWindow.monatt -= 4;
  611. unsafeWindow.frig2 = true;
  612. };
  613. };
  614. };
  615. };
  616.  
  617. if ((unsafeWindow.magic[attacker]['bsr']) || (unsafeWindow.magic[attacker]['rof'])) {
  618. unsafeWindow.monatt += Math.floor((cre_collection[attacker]['defence'] + cre_collection[attacker]['defenceaddon'] + cre_collection[attacker]['ragedefence']) * cre_collection[attacker]['defencemodifier']);
  619. };
  620. if (herd > 0) {
  621. h = herd;
  622. if ((unsafeWindow.magic[h]['mld']) && ((cre_collection[attacker].shooter && shootok==0)||(cre_collection[attacker].shooter!= 1) || cre_collection[attacker].shots==0)) {
  623. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['mld']['effect']) / 100;
  624. };
  625. if ((unsafeWindow.magic[h]['_ia']) && (!cre_collection[attacker]['perseverance'])) {
  626. unsafeWindow.monatt *= (1 - unsafeWindow.magic[h]['_ia']['effect'] / 100);
  627. };
  628. if ((!cre_collection[attacker]['hero']) && (cre_collection[attacker].shooter)&& (cre_collection[attacker].shots!=0) && (unsafeWindow.magic[h]['msk']) && shootok == 1) {
  629. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['msk']['effect']) / 100;
  630. };
  631. };
  632. unsafeWindow.defadd = 0;
  633. if (cre_collection[defender]['agility']) {
  634. if (!unsafeWindow.magic[defender]['agl']) unsafeWindow.defadd = cre_collection[defender]['speed'] * 2;
  635. };
  636. if ((cre_collection[defender]['spirit']) && (!unsafeWindow.magic[defender]['spi'])) {
  637. unsafeWindow.PhysicalModifiers *= 0.5;
  638. };
  639. if ((cre_collection[attacker]['rageagainsttheliving']) && (cre_collection[defender]['alive'])) {
  640. unsafeWindow.PhysicalModifiers *= 1.3;
  641. };
  642. if ((cre_collection[defender]['defensivestance']) && (!unsafeWindow.magic[defender]['mvd'])) {
  643. unsafeWindow.defadd += 5;
  644. };
  645. if ((!cre_collection[defender]['undead']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor'])) {
  646. unsafeWindow.frig2 = false;
  647. unsafeWindow.i = defender;
  648. bigx = cre_collection[i]['big'];
  649. bigy = cre_collection[i]['big'];
  650. if (cre_collection[i]['bigx']) bigx = 1;
  651. if (cre_collection[i]['bigy']) bigy = 1;
  652. unsafeWindow.xd = cre_collection[i]['x'];
  653. unsafeWindow.yd = cre_collection[i]['y'];
  654. for (let xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  655. for (let yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  656. if ((!unsafeWindow.frig2) && (mapobj[yz * defxn + xz] > 0) && (cre_collection[mapobj[yz * defxn + xz]]['side'] != cre_collection[i]['side']) && (cre_collection[mapobj[yz * defxn + xz]]['festeringaura']) && (cre_collection[mapobj[yz * defxn + xz]]['nownumber'] > 0)) {
  657. unsafeWindow.defadd -= 4;
  658. unsafeWindow.frig2 = true;
  659. };
  660. };
  661. };
  662. };
  663. if ((attacker > 0) && (cre_collection[defender]['giantslayer']) && (cre_collection[attacker]['big'])) unsafeWindow.defadd += 4;
  664. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + unsafeWindow.defadd + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  665. if (unsafeWindow.magic[defender]['bsr']) {
  666. unsafeWindow.mondef = 0;
  667. };
  668.  
  669. if ((cre_collection[attacker]['preciseshot']) && (l > 2) && (l <= 9) && (unsafeWindow.rangemod >= 1)) {
  670. unsafeWindow.mondef = 0;
  671. };
  672. if ((cre_collection[attacker]['ignoredefence'])) {
  673. unsafeWindow.mondef *= (1 - cre_collection[attacker]['ignoredefence'] / 100);
  674. };
  675. if (cre_collection[attacker]['crushingleadership']) {
  676. var morale_delta = unsafeWindow.stage.pole.getmorale(attacker) - unsafeWindow.stage.pole.getmorale(defender);
  677. if (morale_delta > 0) {
  678. unsafeWindow.mondef *= Math.max(0, 1 - morale_delta / 10);
  679. };
  680. };
  681. if (cre_collection[attacker]['sacredweapon']) {
  682. var dark_count = get_dark_count(defender);
  683. if (dark_count > 0) {
  684. unsafeWindow.mondef *= Math.max(0, 1 - 0.15 * dark_count);
  685. };
  686. };
  687. if (unsafeWindow.isperk(attacker, _PERK_PIERCING_LUCK)) {
  688. unsafeWindow.mondef *= 1 - Math.max(0, 0.025 * (cre_collection[attacker]['luck'] + cre_collection[attacker]['luckaddon']));
  689. };
  690. if ((cre_collection[defender]['ignoreattack'])) {
  691. unsafeWindow.monatt *= (1 - cre_collection[defender]['ignoreattack'] / 100);
  692. };
  693. if ((cre_collection[attacker]['ridercharge']) && (movelen > 0)) {
  694. unsafeWindow.mondef = unsafeWindow.mondef * (5 - movelen) / 5;
  695. };
  696. if ((cre_collection[attacker]['forcearrow']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  697. unsafeWindow.mondef *= 0.8;
  698. };
  699. if ((cre_collection[attacker]['armorpiercing']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  700. unsafeWindow.mondef *= 0.5;
  701. };
  702. if ((cre_collection[attacker]['jousting']) && (movelen > 0)) {
  703. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.05 * movelen);
  704. };
  705. if (((cre_collection[attacker]['blindingcharge']) || (cre_collection[attacker]['charge'])) && (movelen > 0)) {
  706. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.1 * movelen);
  707. };
  708. if ((cre_collection[defender]['shieldwall']) && (movelen > 0)) {
  709. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * Math.max(0.1, 1 - 0.1 * movelen);
  710. };
  711. if ((unsafeWindow.magic[defender]['enc']) && (unsafeWindow.magic[defender]['enc']['effect'] == 1)) {
  712. unsafeWindow.PhysicalModifiers *= 0.5;
  713. };
  714. if ((cre_collection[attacker]['safeposition']) && (movelen == 0)) {
  715. unsafeWindow.PhysicalModifiers *= 1.5;
  716. };
  717. if ((cre_collection[attacker]['agilesteed']) && (movelen > 0)) {
  718. unsafeWindow.PhysicalModifiers *= 1 - 0.05 * movelen;
  719. };
  720. if (unsafeWindow.mondef < 0) {
  721. unsafeWindow.mondef = 0;
  722. };
  723.  
  724. unsafeWindow.air = 0;
  725. unsafeWindow.fire = 0;
  726. unsafeWindow.water = 0;
  727. unsafeWindow.earth = 0;
  728. if ((hera > 0) && (!cre_collection[attacker]['taran'])) {
  729. h = hera;
  730. if (unsafeWindow.magic[h]['_id']) {
  731. unsafeWindow.mondef *= (1 - unsafeWindow.magic[h]['_id']['effect'] / 100);
  732. };
  733. if (unsafeWindow.magic[h]['_aa']) {
  734. unsafeWindow.air = unsafeWindow.magic[h]['_aa']['effect'] / 100;
  735. };
  736. if (unsafeWindow.magic[h]['_af']) {
  737. unsafeWindow.fire = unsafeWindow.magic[h]['_af']['effect'] / 100;
  738. };
  739. if (unsafeWindow.magic[h]['_aw']) {
  740. unsafeWindow.water = unsafeWindow.magic[h]['_aw']['effect'] / 100;
  741. };
  742. if (unsafeWindow.magic[h]['_ae']) {
  743. unsafeWindow.earth = unsafeWindow.magic[h]['_ae']['effect'] / 100;
  744. };
  745. };
  746. if ((cre_collection[defender]['armoured']) || (cre_collection[defender]['organicarmor'])) {
  747. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  748. };
  749. if (unsafeWindow.monatt < 0) {
  750. unsafeWindow.monatt = 0;
  751. };
  752. if (unsafeWindow.monatt > unsafeWindow.mondef) {
  753. unsafeWindow.AttackDefenseModifier = 1 + (unsafeWindow.monatt - unsafeWindow.mondef) * 0.05;
  754. } else {
  755. unsafeWindow.AttackDefenseModifier = 1 / (1 + (unsafeWindow.mondef - unsafeWindow.monatt) * 0.05);
  756. };
  757. if (cre_collection[attacker]['hero']) {
  758. unsafeWindow.AttackDefenseModifier = 1;
  759. };
  760. var _PERK_ATTACK1 = 8;
  761. var _PERK_ATTACK2 = 9;
  762. var _PERK_ATTACK3 = 10;
  763. var _PERK_DEFENSE1 = 19;
  764. var _PERK_DEFENSE2 = 20;
  765. var _PERK_DEFENSE3 = 21;
  766.  
  767. if ((!cre_collection[attacker]['hero'])&& ((cre_collection[attacker].shooter && shootok == 0)||(cre_collection[attacker].shooter!= 1))) {
  768. if (unsafeWindow.isperk(attacker, _PERK_ATTACK3)) {
  769. unsafeWindow.PhysicalModifiers *= 1.3;
  770. } else {
  771. if (unsafeWindow.isperk(attacker, _PERK_ATTACK2)) {
  772. unsafeWindow.PhysicalModifiers *= 1.2;
  773. } else
  774. if (unsafeWindow.isperk(attacker, _PERK_ATTACK1)) unsafeWindow.PhysicalModifiers *= 1.1;
  775. };
  776. if (unsafeWindow.isperk(defender, _PERK_DEFENSE3)) {
  777. unsafeWindow.PhysicalModifiers *= 0.7;
  778. } else {
  779. if (unsafeWindow.isperk(defender, _PERK_DEFENSE2)) {
  780. unsafeWindow.PhysicalModifiers *= 0.8;
  781. } else {
  782. if (unsafeWindow.isperk(defender, _PERK_DEFENSE1)) unsafeWindow.PhysicalModifiers *= 0.9;
  783. };
  784. };
  785. };
  786. if ((cre_collection[attacker]['siegewalls']) && (cre_collection[defender]['stone'])) {
  787. unsafeWindow.PhysicalModifiers *= 10;
  788. };
  789. var _PERK_COLD_STEEL = 14;
  790. var _PERK_FIERY_WRATH = 101;
  791. var _PERK_HELLFIRE_AURA = 123;
  792. var _PERK_RETRIBUTION = 16;
  793.  
  794. if (unsafeWindow.isperk(attacker, _PERK_COLD_STEEL)) unsafeWindow.water = 1 - (1 - unsafeWindow.water) * (0.9);
  795. if (unsafeWindow.isperk(attacker, _PERK_FIERY_WRATH)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.85);
  796. if (unsafeWindow.isperk(attacker, _PERK_HELLFIRE_AURA)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.95);
  797.  
  798. if (unsafeWindow.magic[attacker]['cre']) {
  799. unsafeWindow.air = 1 - (1 - unsafeWindow.air) * (1 - unsafeWindow.magic[attacker]['cre']['effect'] / 100);
  800. };
  801.  
  802. if (unsafeWindow.isperk(attacker, _PERK_RETRIBUTION)) unsafeWindow.PhysicalModifiers *= (1 + Math.min(Math.max(unsafeWindow.stage.pole.getmorale(attacker, x, y), 0), 5) / 20);
  803. if ((cre_collection[attacker]['viciousstrike']) && (Math.max(0, Math.round((cre_collection[defender]['speed'] + cre_collection[defender]['ragespeed'] + cre_collection[defender]['speedaddon']) * cre_collection[defender]['speedmodifier'])) == 0)) unsafeWindow.PhysicalModifiers *= 1.5;
  804. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.magicmod(attacker, defender, unsafeWindow.fire, unsafeWindow.air, unsafeWindow.water, unsafeWindow.earth, 0.1);
  805. if ((cre_collection[attacker]['bloodfrenzy']) && (unsafeWindow.magic[defender]['fd1'])) {
  806. unsafeWindow.PhysicalModifiers *= 1.3;
  807. };
  808. unsafeWindow.UmelkaModifiers = 1;
  809.  
  810. if ((umelka[cre_collection[attacker]['owner']][0] > 0) && (umelka[cre_collection[defender]['owner']][0] > 0)) {
  811. unsafeWindow.k = umelka[cre_collection[attacker]['owner']][0];
  812. if ((unsafeWindow.k > 0) && (unsafeWindow.k < 11)) {
  813. let j = umelka[cre_collection[defender]['owner']][k];
  814. unsafeWindow.UmelkaModifiers = 1 - j * 0.03;
  815. };
  816. };
  817. unsafeWindow.NumCreatures = cre_collection[attacker]['nownumber'];
  818. let tsc = 0;
  819.  
  820. bigx = cre_collection[defender]['big'];
  821. bigy = cre_collection[defender]['big'];
  822. if (cre_collection[defender]['bigx']) bigx = 1;
  823. if (cre_collection[defender]['bigy']) bigy = 1;
  824. for (var xs = cre_collection[defender]['x'] - 1; xs <= cre_collection[defender]['x'] + 1 + bigx; xs++) {
  825. for (var ys = cre_collection[defender]['y'] - 1; ys <= cre_collection[defender]['y'] + 1 + bigy; ys++) {
  826. if ((mapobj[xs + ys * defxn] > 0) && (mapobj[xs + ys * defxn] != defender) && (cre_collection[mapobj[xs + ys * defxn]]['shieldguard']) && (cre_collection[defender]['side'] == cre_collection[mapobj[xs + ys * defxn]]['side'])) {
  827. tsc++;
  828. };
  829. };
  830. };
  831.  
  832.  
  833. unsafeWindow.PhysicalModifiers /= (tsc + 1);
  834.  
  835. var minmag = 0;
  836. var maxmag = 0;
  837. if ((inuse == 'lep') && (cre_collection[attacker]['crashingleap'])) {
  838. unsafeWindow.Totalmagicdamage = 0;
  839. cre_collection[defender]['attacked'] = 1;
  840. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 4, 'cold', '', 0, 0, 0);
  841. minmag = unsafeWindow.Totalmagicdamage;
  842. unsafeWindow.Totalmagicdamage = 0;
  843. cre_collection[defender]['attacked'] = 1;
  844. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 6, 'cold', '', 0, 0, 0);
  845. maxmag = unsafeWindow.Totalmagicdamage;
  846. };
  847.  
  848. unsafeWindow.mindam = cre_collection[attacker]['mindam'] + cre_collection[attacker]['damageaddon'] + (cre_collection[attacker]['maxdam'] - cre_collection[attacker]['mindam']) * (cre_collection[attacker]['mindamaddon']) + cre_collection[attacker]['ragedamage'];
  849. unsafeWindow.maxdam = cre_collection[attacker]['maxdam'] + cre_collection[attacker]['damageaddon'] - (cre_collection[attacker]['maxdam'] - cre_collection[attacker]['mindam']) * (cre_collection[attacker]['maxdamaddon']) + cre_collection[attacker]['ragedamage'];
  850. h = hera;
  851. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['BLS']) && (unsafeWindow.magic[h]['BLS']['effect'] > 0)) unsafeWindow.mindam = unsafeWindow.maxdam;
  852. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['CRS']) && (unsafeWindow.magic[h]['CRS']['effect'] > 0)) unsafeWindow.maxdam = unsafeWindow.mindam;
  853. if ((cre_collection[attacker]['taran']) && (cre_collection[defender]['stone'])) {
  854. h = hera;
  855. unsafeWindow.mindam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 200 * cre_collection[attacker]['mindam']);
  856. unsafeWindow.maxdam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 400 * cre_collection[attacker]['maxdam']);
  857. };
  858. if (cre_collection[attacker]['accuracy']) unsafeWindow.mindam = unsafeWindow.maxdam;
  859. unsafeWindow.BaseDamage = unsafeWindow.mindam;
  860. unsafeWindow.PhysicalDamage = unsafeWindow.NumCreatures * unsafeWindow.BaseDamage * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + minmag;
  861. unsafeWindow.PhysicalDamage2 = unsafeWindow.NumCreatures * unsafeWindow.maxdam * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + maxmag;
  862. if ((cre_collection[attacker]['deathstrike']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  863. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage) {
  864. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage % cre_collection[defender]['maxhealth'];
  865. };
  866. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage2) {
  867. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage2 % cre_collection[defender]['maxhealth'];
  868. };
  869. };
  870.  
  871. if (cre_collection[attacker]['bladeofslaughter']) {
  872. unsafeWindow.PhysicalDamage += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  873. unsafeWindow.PhysicalDamage2 += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  874. };
  875. if (unsafeWindow.magic[attacker]['brk']) {
  876. unsafeWindow.PhysicalDamage *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  877. unsafeWindow.PhysicalDamage2 *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  878. };
  879. if (unsafeWindow.PhysicalDamage < 1) {
  880. unsafeWindow.PhysicalDamage = 1;
  881. };
  882. if (unsafeWindow.PhysicalDamage2 < 1) {
  883. unsafeWindow.PhysicalDamage2 = 1;
  884. };
  885. if ((cre_collection[attacker]['magicattack']) && (unsafeWindow.l > 2) && (unsafeWindow.stage.pole.issomething(defender, 'dampenmagic'))) unsafeWindow.PhysicalDamage = 0;
  886. if (unsafeWindow.magic[defender]['rag']) {
  887. unsafeWindow.PhysicalDamage = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage);
  888. unsafeWindow.PhysicalDamage2 = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage2);
  889. };
  890. if ((cre_collection[attacker]['vorpalsword']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  891. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'];
  892. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'];
  893. };
  894.  
  895. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage);
  896. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2);
  897. if (cre_collection[defender]['pleasureinpain']) {
  898. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.9);
  899. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.9);
  900. };
  901. if (cre_collection[defender]['raptureinagony']) {
  902. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.8);
  903. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.8);
  904. };
  905. var totalh = (cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'];
  906. unsafeWindow.Uronkills = Math.floor(Math.min(unsafeWindow.PhysicalDamage, totalh) / cre_collection[defender]['maxhealth']);
  907. unsafeWindow.Uronkills2 = Math.floor(Math.min(unsafeWindow.PhysicalDamage2, totalh) / cre_collection[defender]['maxhealth']);
  908. var nowhealth = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage, totalh) - unsafeWindow.Uronkills * cre_collection[defender]['maxhealth']);
  909. var nowhealth2 = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage2, totalh) - unsafeWindow.Uronkills2 * cre_collection[defender]['maxhealth']);
  910. if (nowhealth <= 0) unsafeWindow.Uronkills++;
  911. if (nowhealth2 <= 0) unsafeWindow.Uronkills2++;
  912. unsafeWindow.tUronkills += unsafeWindow.Uronkills;
  913. unsafeWindow.tUronkills2 += unsafeWindow.Uronkills2;
  914. unsafeWindow.tPhysicalDamage += unsafeWindow.PhysicalDamage;
  915. unsafeWindow.tPhysicalDamage2 += unsafeWindow.PhysicalDamage2;
  916. return movelen
  917. }
  918. function get_dmg_info(attacker_obj_index, defender_obj_index){
  919. let cre_collection = unsafeWindow.stage.pole.obj
  920. let attacker = cre_collection[attacker_obj_index]
  921. let defender = cre_collection[defender_obj_index]
  922. let dmg_dict = attackmonster(attacker_obj_index, attacker.x, attacker.y, defender.x, defender.y, defender_obj_index, GM_getValue("cre_distance"));
  923. let min_damage = unsafeWindow.PhysicalDamage
  924. let max_damage = unsafeWindow.PhysicalDamage2
  925. let min_killed, max_killed;
  926. if (min_damage%defender.maxhealth>defender.nowhealth) min_killed = Math.floor(min_damage/defender.maxhealth) + 1
  927. else min_killed = Math.floor(min_damage/defender.maxhealth)
  928. if (max_damage%defender.maxhealth>defender.nowhealth) max_killed = Math.floor(max_damage/defender.maxhealth) + 1
  929. else max_killed = Math.floor(max_damage/defender.maxhealth)
  930. return {min: min_damage, max: max_damage, min_killed: min_killed, max_killed: max_killed}
  931. }
  932.  
  933. let defender_obj_id = 0
  934. let selected_id = 0
  935. function refresh(){
  936. isOpen = true
  937. let cre_collection = unsafeWindow.stage.pole.obj
  938. battleHelper_display(battleHelper_on)
  939. if (cre_distance_on) {
  940. cre_distance_div.style.display = "inline";
  941. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  942. }
  943. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc], "inline")
  944.  
  945. refresh_button.innerHTML = "Обновить"
  946. let cre_list = Object.values(cre_collection);
  947. cre_list.sort(function(a, b) {
  948. return a.obj_index - b.obj_index;
  949. });
  950. dmg_list_container.innerHTML = "";
  951. [...select.children].forEach(child=>child.remove())
  952. let found_defender = false
  953. cre_list.forEach(defender => {
  954. if (![0,-1].includes(defender.nownumber) && defender.nametxt!="" && defender.side == chosen.side && defender.hero == undefined){
  955. let option_id = `cre_no${cre_list.indexOf(defender)}`
  956. select.insertAdjacentHTML("beforeend", `<option id = "${option_id}" value = "${defender.obj_index}">${defender.nametxt} [${defender.nownumber}] </option>`)
  957. if (!found_defender) {
  958. if (`${defender.obj_index}` == chosen.creature) found_defender = true
  959. defender_obj_id = defender.obj_index
  960. selected_id = [...select.children].indexOf(select.lastChild)
  961. }
  962. }
  963. })
  964. dmg_list_container.insertAdjacentHTML("beforeend", `<div id = "chosen_cre_heading" style="display:inline;">
  965. <span>Урон по </span><span style="color:#ffffff; font-size: 110%; font-weight: bold;">${cre_list[defender_obj_id-1].nametxt} [${cre_list[defender_obj_id-1].nownumber}] :</span>
  966. </div>`)
  967. cre_list.forEach(attacker => {
  968. if (attacker.side == -chosen.side && attacker.nownumber != 0 && attacker.nametxt != "") {
  969. let dmg = get_dmg_info(attacker.obj_index, defender_obj_id)
  970. let practical_overall_hp;
  971. if (cre_list[defender_obj_id-1].attack>attacker.defence){
  972. practical_overall_hp = attacker.maxhealth*attacker.nownumber/(1+0.05*Math.abs(cre_list[defender_obj_id-1].attack-attacker.defence))
  973. }
  974. else {
  975. practical_overall_hp = attacker.maxhealth*attacker.nownumber*(1+0.05*Math.abs(cre_list[defender_obj_id-1].attack-attacker.defence))
  976. }
  977. let row_id = `row_no${cre_list.indexOf(attacker)}`
  978. let koef_string = `(коэф. урона <b>${( ((dmg.max + dmg.min) / 2) / practical_overall_hp ).toFixed(2)}</b>)`
  979. dmg_list_container.insertAdjacentHTML("beforeend", `<p id = "${row_id}"><span style = "text-decoration: underline;color:#bfbfbf" >${attacker.nametxt}</span> [${attacker.nownumber}] --> <b style = "color:#bfbfbf">${dmg.min_killed}-${dmg.max_killed}</b> существ (${dmg.min}-${dmg.max}) ${(attacker.hero == undefined&&coeff_on) ? koef_string : ""} </p>`)
  980. }
  981. })
  982. select.options.item(selected_id).selected = true
  983. }