battle_damage_tooltip

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

当前为 2023-05-03 提交的版本,查看 最新版本

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