battle_damage_tooltip

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

当前为 2024-03-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name battle_damage_tooltip
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.0
  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.  
  17. // Странные способы в некоторых местах обусловлены конфликтом со скриптом battleHelper от omne
  18. let outer_chat = document.getElementById("chat_format");
  19. let atLaunch = true;
  20. const physCalcColor = "#141736";
  21. const magCalcColor = "#150f1c";
  22. const calcHellFireColor = "rgba(255,0,0,0.1)";
  23. outer_chat.insertAdjacentHTML("beforeend", `
  24. <div id="cre_distance_div" style="display: none"></div>
  25. <div id="individual_calc"></div>
  26. <div id="mag_calc"></div>
  27. <div id="dmg_list_container"></div>
  28. <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>
  29. <select style="display : none; background-color: #333; color: white; margin: 10px" id="choose_cre"></select>
  30. <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>
  31. <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> `)
  32.  
  33. let last_individual_calc = {}
  34. let isOpen = false
  35. let ini_weight = 10;
  36. let chosen = { side: 1, creature: "Высшие вампиры", afterSideSwitchCre: { "-1": "", "1": "" } }
  37. let chat = document.getElementById("chat_inside");
  38. let select = document.getElementById("choose_cre")
  39. let refresh_button = document.getElementById("dmg_list_refresh")
  40. let side_button = document.getElementById("change_side")
  41. let collapse_button = document.getElementById("collapse")
  42. let individual_calc = document.querySelector("#individual_calc")
  43. let cre_distance_div = document.querySelector("#cre_distance_div")
  44. const settings_panel = document.querySelector("#webgl_settings_whole")
  45. let dmg_list_container = document.querySelector("#dmg_list_container")
  46. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`;
  47.  
  48. // ========= utils ============
  49. function get_GM_value_if_exists(GM_key, default_value) {
  50. const GM_value = GM_getValue(GM_key)
  51. return GM_value != undefined ? GM_value : default_value;
  52. }
  53.  
  54. function getCurrentBattleSpeed() {
  55. for (let i = 1; i <= 3; i++) {
  56. let div = document.querySelector(`#speed${i}_button`)
  57. if (div.style.display === 'none') continue
  58. if (i === 1) return 2
  59. else if (i === 3) return 1
  60. else return 4
  61. }
  62. }
  63.  
  64. function setBattleSpeed(value) {
  65. if (value === 0) return value
  66. else if (value < 1) {
  67. unsafeWindow.timer_interval = Math.abs(value) * 20;
  68. return value
  69. }
  70. unsafeWindow.animspeed_def = unsafeWindow.animspeed = value
  71. unsafeWindow.animspeed_init = unsafeWindow.animspeed > 4 ? 0.5 : 2;
  72. unsafeWindow.timer_interval = Math.abs(value - 20);
  73. !unsafeWindow.timer_interval && unsafeWindow.timer_interval++;
  74. return value
  75. }
  76.  
  77. function calcKilled(dmg, defender) {
  78. let killed;
  79. if (dmg % defender.maxhealth > defender.nowhealth) killed = Math.floor(dmg / defender.maxhealth) + 1
  80. else killed = Math.floor(dmg / defender.maxhealth);
  81. return killed
  82. }
  83.  
  84. function calcHellFireHTML(attacker, defender, cre_collection, physDamage) {
  85. if (!isperk(attacker.obj_index, 7) || attacker.hero === 1) {
  86. return "";
  87. }
  88. const dmg = calcHellFire(attacker, defender, cre_collection);
  89. const minDamage = dmg + physDamage.min;
  90. const maxDamage = dmg + physDamage.max;
  91. const minKilled = calcKilled(minDamage, defender);
  92. const maxKilled = calcKilled(dmg + physDamage.max, defender);
  93. return `<p id="${0}" style=" background-color: ${calcHellFireColor}">
  94. <span style="color:white; font-size: 90%">Адское пламя: </span> <span style = "color:red">${dmg}</span> <span style = "font-size: 80%">урона</span><br>
  95. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${minKilled}-${maxKilled}</b> существ <span style="color:#ffffff">(${minDamage}-${maxDamage})
  96. </p><br>`;
  97. }
  98.  
  99. function calcMagicHTML(attacker, defender, cre_collection, dmg, inList = false) {
  100. if (!mag_damage_on) return "";
  101. let calcHTML = "";
  102. const disclaimerHTML = `<span class="tooltip"> !!! <span class="tooltiptext" style = "width:3000%; transform: translateX(-30%);"> КБО) это заклинание показывает <br> неправильный урон </span>
  103. </span>`;
  104.  
  105. const incorrectSpellIDs = ["circle_of_winter", "swarm", "stormcaller"];
  106. // если темная сила, то дописать урон с усилком
  107. const isPowered = attacker.hero && unsafeWindow.isperk(attacker.obj_index, 6) ? true : false;
  108. for (let spellID of Object.keys(damageSpells)) {
  109. let additionalInfoHTML = "";
  110. if (attacker[spellID]) {
  111. if (spellID === "calllightning") spellID = "lighting";
  112. const dmg = unsafeWindow.stage.pole.calcmagic_script(attacker.x, attacker.y, defender.x, defender.y, spellID);
  113. if (spellID === "meteor") {
  114. let meteorText = "Целей:<br>";
  115. for (let i = 1; i <= 4; i++) {
  116. let dmg2 = Math.floor(dmg * Math.pow(0.85, i));
  117. let killed2 = calcKilled(dmg2, defender);
  118. const poweredDamage = Math.round(dmg2 * 1.5);
  119. const poweredKilled = calcKilled(poweredDamage, defender);
  120. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  121. meteorText += `[${i+1}]: ${killed2} существ (${dmg2}) ${poweredDamageText}<br>`;
  122. }
  123. additionalInfoHTML = `<span class="tooltip"> +++ <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"}">${meteorText}</span>
  124. </span>`;
  125. }
  126. if (spellID === "chainlighting") {
  127. let chainText = "Цель №<br>";
  128. const penaltyArr = Array(0.5, 0.25, 0.125);
  129. for (let i = 0; i < 3; i++) {
  130. let dmg2 = unsafeWindow.stage.pole.calcmagic_script(attacker.x, attacker.y, defender.x, defender.y, spellID, penaltyArr[i]);
  131. let killed2 = calcKilled(dmg2, defender);
  132. const poweredDamage = Math.round(dmg2 * 1.5);
  133. const poweredKilled = calcKilled(poweredDamage, defender);
  134. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  135. chainText += `${i+2} : ${killed2} существ (${dmg2}) ${poweredDamageText}<br>`;
  136. }
  137. additionalInfoHTML = `<span class="tooltip"> +++ <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"};">${chainText}</span>
  138. </span>`;
  139. }
  140. if (spellID === "poison") {
  141. additionalInfoHTML = `<span class="tooltip"> !!! <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"};">Погрешность +-10%</span>
  142. </span>`;
  143. }
  144. let killed = calcKilled(dmg, defender);
  145. const poweredDamage = Math.round(dmg * 1.5);
  146. const poweredKilled = calcKilled(poweredDamage, defender);
  147. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  148. // calcHTML+= `${damageSpells[spellID]} ---> ${dmg} \t (${killed} существ)`;
  149. calcHTML += `<p id="${0}" style=" background-color: ${magCalcColor}">
  150. <span style="color:white; font-size: 90%">${damageSpells[spellID]}: </span><br>
  151. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${killed}</b> существ <span style="color:#ffffff">(${dmg}) ${poweredDamageText}</span> ${incorrectSpellIDs.includes(spellID) ? disclaimerHTML : additionalInfoHTML}
  152. </p>`;
  153. }
  154. }
  155. calcHTML += "<br>";
  156. return calcHTML;
  157. }
  158.  
  159. function calcPhysHTML(attacker, defender, dmg, distance_str) {
  160. return ` <div id="individual_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  161. ${distance_str}
  162. <span>Урон <br>
  163. </span>
  164. <span>
  165. <b>${attacker.nametxt}</b> ${attacker.hero === 1 ? "" : ("[" + attacker.nownumber + "]")} по <b>${defender.nametxt}</b> [${defender.nownumber}]: <br>
  166. <br>
  167. </span>
  168. </div>
  169. <p id="${0}" style=" background-color: ${physCalcColor}">
  170. <span style=color:#bfbfbf"></span>
  171. <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>)
  172. </p>
  173. <br>`;
  174. }
  175.  
  176. function individual_calc_innerHTML(atk_obj_index, def_obj_index) {
  177. if (atk_obj_index === undefined || def_obj_index === undefined) return "";
  178. let cre_collection = unsafeWindow.stage.pole.obj;
  179. let attacker = cre_collection[atk_obj_index];
  180. let defender = cre_collection[def_obj_index];
  181. let dmg = get_dmg_info(atk_obj_index, def_obj_index);
  182. let distance_str = dmg.distance === "" ? "" : `<p> Прыжок на <u>${dmg.distance}</u> клеток </p>`;
  183. last_individual_calc.atk_obj_index = atk_obj_index;
  184. last_individual_calc.def_obj_index = def_obj_index;
  185. let calcHTML = calcPhysHTML(attacker, defender, dmg, distance_str) + calcHellFireHTML(attacker, defender, cre_collection, dmg) + (lastturn > 0 ? calcMagicHTML(attacker, defender, cre_collection, dmg) : "");
  186.  
  187. return calcHTML;
  188. }
  189.  
  190. function paint_coords(x, y, color, timeout = 2077) {
  191. let tile = shado[x + y * defxn]
  192. if (tile == undefined) return
  193. tile.fill(color)
  194. set_visible(tile, 1)
  195.  
  196. setTimeout(() => {
  197. tile.fill(null)
  198. set_visible(tile, 0)
  199. }, timeout)
  200. }
  201. // const observer = new MutationObserver((mutationsList, observer) => {
  202. // for (const mutation of mutationsList) {
  203. // if (mutation.type !== 'childList') return
  204. // for (const addedNode of mutation.addedNodes) {
  205. // if (!(addedNode.classList && addedNode.classList.contains('cont') || ["B", "BR"].includes(addedNode.tagName))) continue
  206. // wrap_battlehelper();
  207. // battlehelper_div.style.display = battleHelper_on ? "inline" : "none";
  208. // }
  209. // }
  210. // });
  211.  
  212. function GM_toggle_boolean(GM_key, boolean) {
  213. boolean = !boolean
  214. GM_setValue(GM_key, boolean);
  215. return boolean
  216. }
  217.  
  218. function set_Display(element_arr, displayProperty) {
  219. element_arr.forEach(element => {
  220. if (element == null) return
  221. element.style.display = displayProperty
  222. })
  223. }
  224.  
  225. function readjust_elements() {
  226. chat = document.getElementById("chat_inside");
  227. select = document.getElementById("choose_cre")
  228. refresh_button = document.getElementById("dmg_list_refresh")
  229. side_button = document.getElementById("change_side")
  230. collapse_button = document.getElementById("collapse")
  231. dmg_list_container = document.querySelector("#dmg_list_container")
  232. individual_calc = document.querySelector("#individual_calc")
  233. cre_distance_div = document.querySelector("#cre_distance_div")
  234. }
  235. // -----------------------------------
  236. // ========= Настройки ============
  237.  
  238. let cre_distance = get_GM_value_if_exists('cre_distance', "")
  239. let cre_distance_on = get_GM_value_if_exists('cre_distance_on', false)
  240. let coeff_on = get_GM_value_if_exists('coeff_on', false)
  241. let animation_speed_on = get_GM_value_if_exists("animation_speed_on", false);
  242. let mag_damage_on = get_GM_value_if_exists("mag_damage_on", true);
  243.  
  244. const new_settings = `
  245. <style>
  246. .tooltip {
  247. position: relative;
  248. display: inline-block;
  249. text-size: 150%;
  250. color: brown;
  251. text-decoration: underline;
  252. }
  253.  
  254. .tooltip .tooltiptext {
  255. visibility: hidden;
  256. position: absolute;
  257. bottom: 100%;
  258. left: 50%;
  259. padding: 5px;
  260. background-color: #555;
  261. color: #fff;
  262. border-radius: 6px;
  263. word-wrap: break-word;
  264. }
  265.  
  266. .tooltip:hover .tooltiptext {
  267. visibility: visible;
  268. }
  269. </style>
  270. <div class="info_row">
  271. <label class="checkbox_container">коэф. урона <span class="tooltip">? <span class="tooltiptext" style = "width: 5000%; transform: translateX(-30%);">отношение урон/хп (т.е. у кого больше всех коэф., с того выгоднее начинать. <br>Работает в списке уронов если нажать на "Открыть" в чате)</span>
  272. </span>
  273. <input type="checkbox" checked="true" id="coeff_on">
  274. <span class="checkbox_checkmark"></span>
  275. </label>
  276. </div>
  277. <div class="info_row">
  278. <label class="checkbox_container">Расстояние между стеками <span class="tooltip">? <span class="tooltiptext transform: translateX(-30%);" style = "width: 5000%;">Расстояние между атакующим и защищающимся стеками. Выбирать расстояние стрелочками в текстовом поле снизу. <br>
  279. Влияет на статус урона стрелка (ближний/дальний урон, кривая/прямая стрела),
  280. разбег и прочие абилки, зависящие от расстояния. <br> Если выставить "Расстояние: 1", то стрелок будет считаться заблокированным.
  281. Если выставить расстояние больше 1,
  282. то стрелок будет считаться не заблокированным (даже если рядом с ним вражеское существо). </span>
  283. </span>
  284. <input type="checkbox" checked="true" id="cre_distance_on">
  285. <span class="checkbox_checkmark"></span>
  286. </label>
  287. <input type="number" style="width: 4%; margin: 2px 2px 2px 80px" id="cre_distance" onkeydown="return false;" value=${cre_distance}>
  288. </div>
  289. <div class="info_row">
  290. <label class="checkbox_container">Скорость анимации <span class="tooltip">? <span class="tooltiptext" style = "width: 5000%; transform: translateX(-30%);"> Скорость боевых анимаций. <br> Выбирать расстояние стрелочками в текстовом поле снизу или если зажать кнопку Alt и нажимать на стрелки клавиатуры.<br> Включить/выключить анимацию [Alt + P (русская З)].<br> Анимацию можно как ускорить, так и замедлить.<br>Верхний потолок у скорости 20, нижнего нету.<br> Негативный показатель означает скорость ниже возможной гвдшной. </span>
  291. </span>
  292. <input type="checkbox" checked="true" id="animation_speed_on">
  293. <span class="checkbox_checkmark"></span>
  294. </label>
  295. <input type="number" style="width: 5%; margin: 2px 2px 2px 80px" id="anim_speed" onkeydown="return false;" >
  296. </div>
  297. <div class="info_row">
  298. <label class="checkbox_container">Расчет маг. урона <span class="tooltip"> * <span class="tooltiptext" style = "width: 5000%; transform: translateX(-30%);"> Расчет магического урона не работает во время расстановки
  299. </span></span>
  300. <input type="checkbox" checked="true" id="mag_damage_on">
  301. <span class="checkbox_checkmark"></span>
  302. </label>
  303. </div>
  304. `
  305. settings_panel.insertAdjacentHTML("beforeend", new_settings)
  306.  
  307. let settings_interval = setInterval(() => {
  308. if (Object.keys(unsafeWindow.stage.pole.obj).length !== 0) {
  309. initMagicCalc();
  310.  
  311. document.querySelector("#mag_damage_on").checked = mag_damage_on;
  312. document.querySelector("#coeff_on").checked = coeff_on
  313. document.querySelector("#cre_distance_on").checked = cre_distance_on
  314. document.querySelector("#animation_speed_on").checked = animation_speed_on
  315. let spd = get_GM_value_if_exists("anim_speed", getCurrentBattleSpeed())
  316. document.querySelector("#anim_speed").value = spd
  317. if (GM_getValue("animation_speed_on")) setBattleSpeed(spd);
  318. // без таймаута гвд крашится :\
  319. if (btype === 66) setTimeout(make_ins_but, 1000);
  320. // убрал, чет лагает с этим
  321. clearInterval(settings_interval)
  322. }
  323. }, 300)
  324. const distance_counter = document.getElementById("cre_distance");
  325. const anim_speed_counter = document.querySelector("#anim_speed")
  326.  
  327.  
  328. // ========= Event Listeners ============
  329. document.body.addEventListener('input', function(event) {
  330. switch (event.target.id) {
  331. case "cre_distance":
  332. if (distance_counter.value < 1) {
  333. distance_counter.value = 1
  334. return
  335. }
  336. if (!cre_distance_on) return
  337. GM_setValue('cre_distance', distance_counter.value)
  338. if (isOpen) refresh()
  339. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  340. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  341. break;
  342. case "anim_speed":
  343. if (anim_speed_counter.value > 20) {
  344. anim_speed_counter.value = 20
  345. return
  346. }
  347. GM_setValue('anim_speed', anim_speed_counter.value)
  348. if (!animation_speed_on) return
  349. setBattleSpeed(anim_speed_counter.value)
  350. break;
  351. }
  352. });
  353. const anim_speed_input = document.querySelector('#anim_speed')
  354. document.addEventListener('keydown', event => {
  355. if (!event.altKey) return
  356. if (["P", "p", "з", "З"].includes(event.key)) {
  357. animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
  358. document.querySelector("#animation_speed_on").checked = animation_speed_on
  359. if (animation_speed_on) {
  360. GM_setValue('anim_speed', anim_speed_counter.value)
  361. setBattleSpeed(anim_speed_counter.value);
  362. } else {
  363. setBattleSpeed(getCurrentBattleSpeed());
  364. }
  365. }
  366. if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
  367. event.preventDefault();
  368. const increment = event.key === 'ArrowUp' ? 1 : -1;
  369. anim_speed_input.value = parseInt(anim_speed_input.value) + increment;
  370. anim_speed_input.dispatchEvent(new Event('input', { bubbles: true }));
  371. }
  372. });
  373. document.body.addEventListener('change', function(event) {
  374. switch (event.target.id) {
  375. case "mag_damage_on":
  376. mag_damage_on = GM_toggle_boolean("mag_damage_on", mag_damage_on);
  377. if (isOpen) refresh();
  378. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  379. break;
  380. case "coeff_on":
  381. coeff_on = GM_toggle_boolean("coeff_on", coeff_on);
  382. if (isOpen) refresh();
  383. break;
  384. case "choose_cre":
  385. chosen.creature = select.value
  386. refresh()
  387. break;
  388. case "cre_distance_on":
  389. cre_distance_on = GM_toggle_boolean("cre_distance_on", cre_distance_on)
  390. cre_distance_on ? GM_setValue('cre_distance', distance_counter.value) : GM_setValue('cre_distance', "")
  391. if (cre_distance_on) {
  392. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  393. cre_distance_div.style.display = "inline"
  394. if (isOpen) refresh()
  395. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  396. } else {
  397. cre_distance_div.innerHTML = ""
  398. }
  399. if (isOpen) refresh()
  400. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  401. break;
  402. case "animation_speed_on":
  403. animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
  404. if (animation_speed_on) {
  405. GM_setValue('anim_speed', anim_speed_counter.value)
  406. setBattleSpeed(anim_speed_counter.value);
  407. } else {
  408. setBattleSpeed(getCurrentBattleSpeed());
  409. }
  410. break;
  411. }
  412. });
  413. document.body.addEventListener('click', function(event) {
  414. if (event.target.parentElement && /speed(.)_button/.test(event.target.parentElement.id)) {
  415. setBattleSpeed(getCurrentBattleSpeed());
  416. document.querySelector("#animation_speed_on").checked = false
  417. GM_setValue('animation_speed_on', false)
  418. }
  419. switch (event.target.id) {
  420. case "dmg_list_refresh":
  421. readjust_elements()
  422. refresh()
  423. break
  424. case "change_side":
  425. chosen.afterSideSwitchCre[chosen.side] = chosen.creature
  426. chosen.side = -chosen.side
  427. chosen.creature = chosen.afterSideSwitchCre[chosen.side]
  428. refresh()
  429. break
  430. case "collapse":
  431. readjust_elements()
  432. isOpen = false
  433. refresh_button.innerHTML = "Открыть";
  434. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc, cre_distance_div], "none")
  435. break
  436. // case "confirm_ins_img":
  437. // observer.observe(outer_chat, { childList: true });
  438. // setTimeout(function() {
  439. // observer.disconnect();
  440. // }, 190000);
  441. // break;
  442. }
  443. });
  444.  
  445. function paint_two_coords() {
  446.  
  447. }
  448. // Урон одного стека по другому по выбору нажатием кнопки E
  449. let calc_x, calc_y, magshot_x, magshot_y;
  450. window.addEventListener("keyup", event => {
  451. /* // Должно быть открытие настроек на Esc, но чтоб не мешало в бою надо устранять ситуацию когда открыта инфа о существе и на esc она закрывается
  452. if (event.key === 'Escape'){
  453. for (const panel of document.querySelectorAll(".window_relative")){
  454. if (panel.style.display !== "none" && panel.id !== "win_Settings") {console.log("smth opened already"); return}
  455. }
  456. document.querySelector("#win_Settings").style.display = document.querySelector("#win_Settings").style.display ? '' : 'none';
  457. } */
  458. if ((document.querySelector("#chattext") !== document.activeElement) && (document.querySelector("#chattext_classic") !== document.activeElement)) {
  459. if (["e", "E", "у", "У"].includes(event.key)) {
  460. if (lastturn < 0) {
  461. for (const cre of Object.values(stage.pole.obj)) {
  462. unsafeWindow.mapobj[cre.x + cre.y * defxn] = cre.obj_index;
  463. }
  464. }
  465. let cre_collection = unsafeWindow.stage.pole.obj
  466. if (mapobj[xr_last + yr_last * defxn] === undefined || cre_collection[mapobj[xr_last + yr_last * defxn]].rock === 1) {
  467. paint_coords(xr_last, yr_last, "#cccccc")
  468. return
  469. }
  470. if (calc_x === undefined) {
  471. [calc_x, calc_y] = [xr_last, yr_last];
  472. paint_coords(xr_last, yr_last, "#800000");
  473. let attacker = cre_collection[mapobj[calc_x + calc_y * defxn]]
  474. if (attacker.hero === 1) {
  475. readjust_elements();
  476. individual_calc.innerHTML = ` <div id="individual_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  477. <span>Урон <br>
  478. </span>
  479. <b>${attacker.nametxt}</b> по
  480. <br>
  481. </div>
  482. `;
  483. }
  484. } else {
  485. readjust_elements();
  486. let atk_obj_index = unsafeWindow.mapobj[calc_x + calc_y * defxn]
  487. let def_obj_index = unsafeWindow.mapobj[xr_last + yr_last * defxn]
  488. set_Display([individual_calc, collapse_button], "inline")
  489. if (cre_distance_on) {
  490. cre_distance_div.style.display = "inline";
  491. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  492. }
  493. individual_calc.innerHTML = individual_calc_innerHTML(atk_obj_index, def_obj_index);
  494. calc_x = calc_y = undefined
  495. paint_coords(xr_last, yr_last, "blue")
  496. }
  497. }
  498.  
  499. if (["u", "U", "г", "Г"].includes(event.key)) {
  500. //if (["N", "n", "т", "Т"].includes(event.key)) {
  501.  
  502. if (!magshot_x) {
  503. [magshot_x, magshot_y] = [xr_last, yr_last]
  504. paint_coords(xr_last, yr_last, "#FC7052", 4000)
  505. } else {
  506. paint_coords(xr_last, yr_last, "#7A71FE", 4000)
  507. magshot(magshot_x, magshot_y, xr_last, yr_last)
  508. magshot_x = magshot_y = null
  509. }
  510. }
  511. }
  512. });
  513. // -----------------------------------
  514.  
  515. // ========= battleHelper ============
  516. // function wrap_battlehelper() {
  517. // for (const child of battlehelper_div.children) {
  518. // if (child.className === "cont") return
  519. // }
  520. // readjust_elements();
  521. // let el_transfer = [];
  522. // [...outer_chat.children].forEach(child => {
  523. // if (["B", "BR"].includes(child.tagName) || child.className == "cont") {
  524. // el_transfer.push(child)
  525. // }
  526. // });
  527. // for (const el of el_transfer) battlehelper_div.appendChild(el);
  528. // const first_icons = battlehelper_div.querySelectorAll('br + div.cont');
  529. // let teams_text = [...outer_chat.childNodes].filter(node => (node.nodeType === node.TEXT_NODE && /Команда №(\d)/.test(node.textContent.trim())));
  530. // let i = 0
  531. // for (const img_div of first_icons) {
  532. // img_div.previousSibling.insertAdjacentHTML('beforebegin', teams_text[i].textContent);
  533. // i++;
  534. // }
  535. // for (const el of teams_text) el.remove()
  536. // let title_arr = [...battlehelper_div.children].filter(child => child.textContent === "Стартовый бонус АТБ")
  537. // if (battlehelper_div.children.length === 2 && title_arr.length === 1) {
  538. // battlehelper_div.innerHTML = " "
  539. // }
  540. // }
  541. // observer.observe(outer_chat, { childList: true });
  542. // setTimeout(function() {
  543. // observer.disconnect();
  544. // }, 30000);
  545.  
  546. // -----------------------------------
  547. // ========= маг. урон ============
  548.  
  549. const damageSpells = {
  550. "meteor": "Метеоритный дождь",
  551. "lighting": "Молния",
  552. "fireball": "Огненный шар",
  553. "chainlighting": "Цепная молния",
  554. "firewall": "Огненная стена",
  555. "magicarrow": "Магическая стрела",
  556. "stonespikes": "Каменные шипы",
  557. "magicfist": "Магический кулак",
  558. "icebolt": "Ледяная глыба",
  559. "circle_of_winter": "Кольцо холода",
  560. "swarm": "Осиный рой",
  561. "angerofhorde": "Ярость орды",
  562. "poison": "Разложение",
  563. "stormcaller": "Зов бури",
  564. "calllightning": "Зов молний",
  565. }
  566.  
  567. function calcFactionModifier(attacker, defender) {
  568. let modifier, k;
  569. if ((umelka[attacker['owner']][0] > 0) && (umelka[defender['owner']][0] > 0)) {
  570. k = umelka[attacker['owner']][0];
  571. if ((k > 0) && (k < 11)) {
  572. let j = umelka[defender['owner']][k];
  573. modifier = 1 - j * 0.03;
  574. };
  575. };
  576. return modifier;
  577. }
  578.  
  579. function calcHellFire(attacker, defender, cre_collection) {
  580. const factionModifier = calcFactionModifier(attacker, defender);
  581. const spellPower = cre_collection[heroes[attacker.owner]].maxnumber;
  582. const perkModifier = isperk(attacker.obj_index, 104) ? 1.5 : 1;
  583. // console.log("round: ", Math.round((7 * spellPower + 7) * perkModifier) * factionModifier);
  584. const res = Math.floor(Math.round((7 * spellPower + 7) * perkModifier) * factionModifier);
  585. // console.log("floor: ", Math.floor((7 * spellPower + 7) * perkModifier) * factionModifier);
  586. // return Math.round((7 * spellPower + 7) * perkModifier * factionModifier);
  587. return res;
  588. }
  589. // добавление spellname_magiceff для объекта для дальнийших расчетов
  590. function initEff(s, activeobj_S) { // s = spell name
  591. if (stage[war_scr].obj[activeobj_S][s + 'effmain'] > 0) {
  592. let eff;
  593. if (stage[war_scr].obj[activeobj_S].hero) {
  594. var s1 = 0;
  595. if ((isperk(activeobj_S, 93)) && ((s == 'magicfist') || (s == 'raisedead'))) { s1 = 4; };
  596. if ((isperk(activeobj_S, 78)) && ((s == 'poison') || (s == 'mpoison'))) { s1 += 5; };
  597. if ((isperk(activeobj_S, 89)) && ((s == 'poison') || (s == 'mpoison'))) { s1 += 3; };
  598. eff = (stage[war_scr].obj[activeobj_S][s + 'effmain'] + stage[war_scr].obj[activeobj_S][s + 'effmult'] * (stage[war_scr].getspellpower(activeobj_S, s) + s1));
  599. if (stage[war_scr].obj[activeobj_S][s + 'effmult'] == 1.5) { eff = Math.round(eff); };
  600. var teff = eff;
  601. } else {
  602. eff = Math.round(stage[war_scr].obj[activeobj_S][s + 'effmain'] + stage[war_scr].obj[activeobj_S][s + 'effmult'] * Math.pow(stage[war_scr].obj[activeobj_S]['nownumber'], 0.7));
  603. if (s == 'blind') {
  604. eff = Math.round(stage[war_scr].obj[activeobj_S][s + 'effmain'] + stage[war_scr].obj[activeobj_S][s + 'effmult'] * stage[war_scr].obj[activeobj_S]['nownumber']);
  605. };
  606. var teff = eff;
  607. }
  608. stage[war_scr].obj[activeobj_S][s + '_magiceff'] = eff;
  609. }
  610. }
  611.  
  612. function initMagicCalc() {
  613.  
  614.  
  615. // родной calcmagic с удалением кодом массовых заклов и др. побочных эффектов наведения курсора с активным заклом
  616. unsafeWindow.stage.pole.calcmagic_script = function calcmagic(atk_x, atk_y, xr, yr, magicuse, penalty = 1) {
  617. console.log(magicuse);
  618. let i = mapobj[atk_x + defxn * atk_y];
  619. const activeobj_S = i;
  620. initEff(magicuse, i);
  621. unsafeWindow.Totalmagicdamage = 0;
  622. unsafeWindow.Totalmagickills = 0;
  623.  
  624. var ok = false;
  625. unsafeWindow.mul = 1;
  626. var len = unsafeWindow.stage.pole.obj_array.length;
  627. for (var k1 = 0; k1 < len; k1++) {
  628. var j = unsafeWindow.stage.pole.obj_array[k1];
  629. unsafeWindow.stage.pole.obj[j]['attacked'] = 1;
  630. unsafeWindow.stage.pole.obj[j]['attacked2'] = 1;
  631. };
  632.  
  633. if ((magicuse == 'magicfist') || (magicuse == 'angerofhorde')) {
  634. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  635. if ((magicuse == 'magicfist') && (unsafeWindow.stage.pole.obj[mapobj[xr + yr * defxn]]['organicarmor'])) eff = Math.round(eff * 0.2);
  636. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], eff, 'neutral', magicuse, 0, 0, 0);
  637. ok = true;
  638. };
  639. if (magicuse == 'swarm') {
  640. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'], 'other', magicuse, 0, 0, 0);
  641. ok = true;
  642. };
  643.  
  644. if ((magicuse == 'magicarrow') || (magicuse == 'lighting')) {
  645. if (unsafeWindow.stage.pole.obj[activeobj_S]['calllightning']) {
  646. unsafeWindow.stage.pole.obj[activeobj_S]['lighting_magiceff'] = 50 * unsafeWindow.stage.pole.obj[activeobj_S]['nownumber'];
  647. };
  648. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'air', magicuse, 0, 0, 0);
  649. ok = true;
  650. };
  651. if (magicuse == 'icebolt') {
  652. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'cold', magicuse, 0, 0, 0);
  653. ok = true;
  654. };
  655. if (magicuse == 'implosion') {
  656. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  657. ok = true;
  658. };
  659.  
  660. if (magicuse == 'poison') {
  661. unsafeWindow.stage.pole.calcpoison(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff']);
  662. ok = true;
  663. };
  664. if (magicuse == 'meteor') {
  665. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  666. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(eff * mul), 'earth', magicuse, 0, 0, 0);
  667. ok = true;
  668. };
  669. if (magicuse == 'chainlighting') {
  670. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  671. if (unsafeWindow.stage.pole.obj[activeobj_S]['spmult'] > 1) {
  672. eff = Math.round(unsafeWindow.stage.pole.obj[activeobj_S]['spmult'] * (unsafeWindow.stage.pole.obj[activeobj_S]['chainlightingeffmain'] + unsafeWindow.stage.pole.obj[activeobj_S]['chainlightingeffmult'] * Math.pow(unsafeWindow.stage.pole.obj[activeobj_S]['nownumber'], 0.7)));
  673. }
  674. if (penalty === 1) {
  675. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(eff * mul), 'air', 'lighting', 0, 0, 0);
  676. } else {
  677. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.floor(Math.round(eff * mul) * penalty), 'air', 'lighting', 0, 0, 0);
  678. }
  679. ok = true;
  680. };
  681.  
  682. if (magicuse == 'fireball') {
  683. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'fire', magicuse, 0, 0, 0);
  684. ok = true;
  685. };
  686. if (magicuse == 'stormcaller') {
  687. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S].nownumber * 10), 'air', magicuse, 0, 0, 0);
  688. ok = true;
  689. };
  690. if (magicuse == 'firewall') {
  691. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'], 'fire', magicuse, 0, 0, 0);
  692. ok = true;
  693. };
  694. if (magicuse == 'circle_of_winter') {
  695. console.log("mul", mul);
  696. console.log("eff", unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff']);
  697. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'water', magicuse, 0, 0, 0);
  698. ok = true;
  699. };
  700.  
  701. if (magicuse == 'stonespikes') {
  702. // unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn + 1], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  703. // unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn - 1], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  704. // unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + (yr + 1) * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  705. // unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + (yr - 1) * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  706. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'] * mul), 'earth', magicuse, 0, 0, 0);
  707. ok = true;
  708. };
  709. // if ((ok) && (magicuse != '') && ((magicuse == 'circle_of_winter') || (magicuse == 'icebolt')) && (((unsafeWindow.stage.pole.obj[activeobj_S]['hero']) && (isperk(activeobj_S, 99))) || (unsafeWindow.stage.pole.obj[activeobj_S]['master_of_ice']))) {
  710. // unsafeWindow.stage.pole.showatb();
  711. // };
  712.  
  713. // if ((ok) && (magicuse != '') && (unsafeWindow.stage.pole.obj[activeobj_S][magicuse + 'elem'] == 'air') && (((unsafeWindow.stage.pole.obj[activeobj_S]['hero']) && (isperk(activeobj_S, 100))) || (unsafeWindow.stage.pole.obj[activeobj_S]['master_of_storms']))) {
  714. // unsafeWindow.stage.pole.showatb();
  715. // };
  716. return Totalmagicdamage;
  717. };
  718. // копипаст с удаленем запрета на показ урона по своим стекам
  719. stage.pole.attackmagic = function attackmagic(attacker, defender, eff, element, iname, noexp, nodamage, nomult) {
  720. if (defender == 1000) return 0;
  721. if ((defender <= 0) || (defender == undefined) || (!this.obj[defender])) return 0;
  722. // if (this.obj[attacker].getside()==this.obj[defender]['side']) return 0;
  723. if ((this.obj[defender]['rock']) || (this.obj[defender]['hero'])) return 0;
  724. if (!nomult) nomult = 0;
  725. if (this.obj[defender]['y'] < 0) return 0;
  726. if (this.obj[defender]['attacked'] != 1) return 0;
  727.  
  728. if ((magic[attacker]['apc']) && (magic[attacker]['apc']['effect'] > 0)) {
  729. eff *= magic[attacker]['apc']['effect'] / 100;
  730. };
  731. if (this.obj[defender]['building']) {
  732. eff *= 0.05;
  733. };
  734. if ((magic[defender]['enc']) && (magic[defender]['enc']['effect'] == 1)) {
  735. eff *= 0.5;
  736. };
  737.  
  738. if (this.obj[attacker]['forbiddenspell']) {
  739. eff *= this.check_forbiddenspell(attacker);
  740.  
  741. }
  742.  
  743. this.obj[defender]['attacked'] = 0;
  744. if ((this.obj[defender]['owner'] == 2) && ((is_naim_guild(btype)) || ((btype != 13) && (plid2 == -2))) && (this.obj[attacker]['hero'])) {
  745. eff *= checkmage(this.obj[attacker]['owner'], iname);
  746. };
  747.  
  748. if ((btype == 108) && (checkwall2(this.obj[attacker]['x'], this.obj[attacker]['y'], this.obj[defender]['x'], this.obj[defender]['y'], attacker))) eff *= 0.5;
  749. if ((btype == 118) && (checkwall2(this.obj[attacker]['x'], this.obj[attacker]['y'], this.obj[defender]['x'], this.obj[defender]['y'], attacker))) eff *= 0.5;
  750.  
  751.  
  752. var hera = 0;
  753. var herd = 0;
  754. var len = this.obj_array.length;
  755. for (var k1 = 0; k1 < len; k1++) {
  756. var k = this.obj_array[k1];
  757. if ((this.obj[k].hero) && (this.obj[k].owner == this.obj[attacker].owner)) hera = k;
  758. if ((this.obj[k].hero) && (this.obj[k].owner == this.obj[defender].owner)) herd = k;
  759. };
  760.  
  761. if ((hera > 0) && (magic[hera]['bna'])) {
  762. eff = eff * (1 + magic[hera]['bna']['effect'] / 100);
  763. };
  764. if ((!this.obj[attacker]['hero']) && (isperk(attacker, _PERK_BLESS))) {
  765. eff *= 1.04;
  766. };
  767. if ((herd > 0) && (magic[herd]['bnd'])) {
  768. eff = eff / (1 + magic[herd]['bnd']['effect'] / 100);
  769. };
  770. if ((herd > 0) && (magic[herd]['fld'])) {
  771. eff = eff * (1 - magic[herd]['fld']['effect'] / 100);
  772. };
  773. if ((herd > 0) && (magic[herd]['rcd']) && (monster_race[this.obj[attacker]['id']] == magic[herd]['rcd']['effect'])) {
  774. eff = eff * 0.93;
  775. };
  776.  
  777. if ((!this.obj[attacker]['hero']) && (magic[attacker]['zat']) && ((magic[attacker]['zat']['effect'] == 1) || (magic[attacker]['zat']['effect'] == 2))) {
  778. eff *= 1.15;
  779. };
  780.  
  781.  
  782. if ((magic[defender]['sum']) && (isperk(attacker, _PERK_EXORCISM)) && (nomult == 0)) {
  783. eff *= 2;
  784. };
  785.  
  786.  
  787. //eff1=24 eff2=24 eff3=31.056 eff4=27.28 imm=70.6 imm2=83.0068 eff5=22.64425504
  788. eff = this.calceffmagic(attacker, defender, eff, element);
  789. ignor = 0;
  790. if ((magic[defender]['mmn']) && (element != 'neutral')) {
  791. eff *= 1 + magic[defender]['mmn']['effect'] / 100;
  792. }
  793.  
  794. if ((hera > 0) && (this.obj[hera]['hero'])) {
  795. h = hera;
  796. if (nomult == 0) {
  797. if ((magic[h]['_en']) && (element == 'neutral')) {
  798. eff *= 1 + magic[h]['_en']['effect'] / 100;
  799. };
  800. if ((magic[h]['_ea']) && (element == 'air')) {
  801. eff *= 1 + magic[h]['_ea']['effect'] / 100;
  802. };
  803. if ((magic[h]['_ew']) && (element == 'cold')) {
  804. eff *= 1 + magic[h]['_ew']['effect'] / 100;
  805. };
  806. if ((magic[h]['_ef']) && (element == 'fire')) {
  807. eff *= 1 + magic[h]['_ef']['effect'] / 100;
  808. };
  809. if ((magic[h]['_ee']) && (element == 'earth')) {
  810. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  811. };
  812. };
  813.  
  814. if ((magic[h]['_Ia']) && ((element == 'air') || (iname == 'lighting'))) {
  815. ignor = magic[h]['_Ia']['effect'] / 100;
  816. };
  817. if ((magic[h]['_Iw']) && (element == 'cold')) {
  818. ignor = magic[h]['_Iw']['effect'] / 100;
  819. };
  820. if ((magic[h]['_If']) && (element == 'fire')) {
  821. ignor = magic[h]['_If']['effect'] / 100;
  822. };
  823. if ((magic[h]['_Ie']) && (element == 'earth')) {
  824. ignor = magic[h]['_Ie']['effect'] / 100;
  825. };
  826. };
  827.  
  828. magicdamage = Math.round(eff);
  829. if ((umelka[this.obj[attacker]['owner']][0] > 0) && (umelka[this.obj[defender]['owner']][0] > 0)) {
  830. var k = umelka[this.obj[attacker]['owner']][0];
  831. if ((k > 0) && (k < 11)) {
  832. j = umelka[this.obj[defender]['owner']][k];
  833. magicdamage = magicdamage * (100 - j * 3) / 100;
  834. };
  835. };
  836.  
  837. immune = this.getattackimmune(attacker, defender, element, iname, 1);
  838. if (hera > 0) {
  839. h = hera;
  840. if ((magic[h]['nut']) && (plid2 == -2)) {
  841. magicdamage = magicdamage * (100 + magic[h]['nut']['effect']) / 100;
  842. };
  843. if ((magic[h]['imd'])) {
  844. ignor = 1 - (1 - ignor) * (1 - magic[h]['imd']['effect'] / 100);
  845. };
  846. if ((this.obj[defender]['mechanical']) && (magic[hera]['MEC']) && (element == 'neutral')) {
  847. magicdamage *= 1 + magic[hera]['MEC']['effect'] / 100;
  848. };
  849. };
  850.  
  851.  
  852.  
  853. if (isperk(defender, _PERK_BONEWARD)) {
  854. immune *= 0.8;
  855. };
  856. immune2 = 0;
  857. if (element != 'neutral') {
  858. var xx = 0,
  859. yy = 0,
  860. xx1 = 0,
  861. yy1 = 0;
  862.  
  863. var bigx = this.obj[defender]['big'];
  864. var bigy = this.obj[defender]['big'];
  865. if (this.obj[defender]['bigx']) bigx = 1;
  866. if (this.obj[defender]['bigy']) bigy = 1;
  867.  
  868. for (xx = -1; xx <= 1 + bigx; xx++) {
  869. for (yy = -1; yy <= 1 + bigy; yy++) {
  870. xx1 = this.obj[defender]['x'] + xx;
  871. yy1 = this.obj[defender]['y'] + yy;
  872. if ((mapobj[xx1 + yy1 * defxn] > 0) && (!this.obj[defender]['magnetism']) && (this.obj[mapobj[xx1 + yy1 * defxn]]['side'] == this.obj[defender]['side']) && (this.obj[mapobj[xx1 + yy1 * defxn]]['magnetism'])) {
  873. if (immune2 < this.obj[mapobj[xx1 + yy1 * defxn]]['nownumber']) {
  874. immune2 = this.obj[mapobj[xx1 + yy1 * defxn]]['nownumber'];
  875. var mg = mapobj[xx1 + yy1 * defxn];
  876. };
  877. break;
  878. };
  879. };
  880. };
  881. immune2 = Math.min(100, immune2);
  882. if ((this.obj[defender]['enchantedarmor']) && (this.obj[defender]['nownumber'] > 0) && (this.obj[attacker]['side'] == this.obj[defender]['side'])) { immune2 = 100; var mg = defender; };
  883. };
  884. if (this.obj[defender]['organicarmor']) ignor = 0;
  885. immune1 = (100 - (100 - immune) * (1 - ignor));
  886. dambefore = Math.round(magicdamage * immune1 / 100);
  887. immune *= 1 - immune2 / 100;
  888. immune = (100 - (100 - immune) * (1 - ignor));
  889.  
  890.  
  891.  
  892. magicdamage = Math.round(magicdamage * immune / 100);
  893.  
  894.  
  895. if (magic[defender]['rag']) {
  896. magicdamage = this.ragedamage(defender, magicdamage);
  897. };
  898.  
  899.  
  900. Totalmagicdamage += magicdamage;
  901. var totalh = (this.obj[defender]['nownumber'] - 1) * this.obj[defender]['maxhealth'] + this.obj[defender]['nowhealth'];
  902. var kills = Math.floor(Math.min(magicdamage, totalh) / this.obj[defender]['maxhealth']);
  903. var nowhealth = this.obj[defender]['nowhealth'] - (Math.min(magicdamage, totalh) - kills * this.obj[defender]['maxhealth']);
  904. if (nowhealth <= 0) kills++;
  905. Totalmagickills += kills;
  906.  
  907. if ((magicuse != '') && (defender > 0) && (this.obj[attacker][magicuse + 'elem'] == 'air') && (((this.obj[attacker]['hero']) && (isperk(attacker, 100 /*_PERK_MASTER_OF_STORMS*/ ))) || (this.obj[activeobj]['master_of_storms']))) {
  908. var a = 0.3;
  909. if (this.obj[activeobj]['master_of_storms']) a = this.obj[activeobj]['master_of_storms'] / 100;
  910. init = Math.floor((100 - this.obj[defender]['nowinit'] + this.obj[attacker]['nowinit']) * a);
  911. this.obj[defender]['reset_init'] = init;
  912. };
  913. if ((magicuse != '') && ((magicuse == 'circle_of_winter') || (magicuse == 'icebolt')) && (((this.obj[activeobj]['hero']) && (isperk(activeobj, 99 /*_PERK_MASTER_OF_ICE*/ ))) || (this.obj[activeobj]['master_of_ice']))) {
  914. var a = 30;
  915. if (this.obj[activeobj]['master_of_ice']) a = this.obj[activeobj]['master_of_ice'];
  916. setn_temp_magic(defender, 'cld', a);
  917. };
  918.  
  919.  
  920. }
  921. stage.pole.calcpoison = function calcpoison(i, j, eff) {
  922. var defender = j;
  923. var attacker = i;
  924.  
  925. function experimental() {
  926. if ((magic[attacker]['apc']) && (magic[attacker]['apc']['effect'] > 0)) {
  927. eff *= magic[attacker]['apc']['effect'] / 100;
  928. };
  929. if (stage.pole.obj[attacker]['forbiddenspell']) {
  930. eff *= stage.pole.check_forbiddenspell(attacker);
  931. }
  932. if ((!stage.pole.obj[attacker]['hero']) && (isperk(attacker, _PERK_BLESS))) {
  933. eff *= 1.04;
  934. };
  935. if ((herd > 0) && (magic[herd]['fld'])) {
  936. eff = eff * (1 - magic[herd]['fld']['effect'] / 100);
  937. };
  938. if ((herd > 0) && (magic[herd]['rcd']) && (monster_race[stage.pole.obj[attacker]['id']] == magic[herd]['rcd']['effect'])) {
  939. eff = eff * 0.93;
  940. };
  941. if ((!stage.pole.obj[attacker]['hero']) && (magic[attacker]['zat']) && ((magic[attacker]['zat']['effect'] == 1) || (magic[attacker]['zat']['effect'] == 2))) {
  942. eff *= 1.15;
  943. };
  944. if ((magic[defender]['sum']) && (isperk(attacker, _PERK_EXORCISM)) && (nomult == 0)) {
  945. eff *= 2;
  946. };
  947.  
  948. if ((hera > 0) && (stage.pole.obj[hera]['hero'])) {
  949. h = hera;
  950. if (nomult == 0) {
  951. if ((magic[h]['_ee'])) {
  952. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  953. };
  954. };
  955. if ((magic[h]['_Ie'])) {
  956. ignor = magic[h]['_Ie']['effect'] / 100;
  957. };
  958. };
  959.  
  960.  
  961. }
  962. //experimental();
  963.  
  964. if ((defender <= 0) || (defender == undefined)) return 0;
  965. // if (stage.pole.obj[attacker].getside() == stage.pole.obj[defender]['side']) return 0;
  966. if ((stage.pole.obj[defender]['rock']) || (stage.pole.obj[defender]['hero'])) return 0;
  967. if (stage.pole.obj[defender]['y'] < 0) return 0;
  968. if (stage.pole.obj[defender]['attacked'] != 1) return 0;
  969. stage.pole.obj[defender]['attacked'] = 0;
  970. var hera = 0;
  971. var herd = 0;
  972. var attacker = i;
  973. var len = stage.pole.obj_array.length;
  974. for (var k1 = 0; k1 < len; k1++) {
  975. var k = stage.pole.obj_array[k1];
  976. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[attacker].owner)) hera = k;
  977. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[defender].owner)) herd = k;
  978. };
  979. if (stage.pole.obj[j]['absolutepurity']) eff = 0;
  980. if (stage.pole.obj[j]['building']) eff *= 0.05;
  981. if (hera > 0) {
  982. h = hera;
  983. if (magic[h]['_ee']) {
  984. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  985. };
  986. eff = Math.round(eff);
  987. if ((hera > 0) && (magic[hera]['bna'])) {
  988. eff = Math.round(eff * (1 + magic[hera]['bna']['effect'] / 100));
  989. };
  990. if ((herd > 0) && (magic[herd]['bnd'])) {
  991. eff = Math.round(eff / (1 + tmagic[herd]['bnd']['effect'] / 100));
  992. };
  993. if (stage.pole.obj[j]['vulnerabletoshadowmagic']) eff *= 1.25;
  994. };
  995. eff = Math.round(eff);
  996. var magicdamage = eff;
  997. if ((umelka[stage.pole.obj[attacker]['owner']][0] > 0) && (umelka[stage.pole.obj[defender]['owner']][0] > 0)) {
  998. var k = umelka[stage.pole.obj[attacker]['owner']][0];
  999. if ((k > 0) && (k < 11)) {
  1000. j = umelka[stage.pole.obj[defender]['owner']][k];
  1001. magicdamage = magicdamage * (100 - j * 3) / 100;
  1002. };
  1003. };
  1004. magicdamage = Math.round(magicdamage);
  1005.  
  1006. Totalmagicdamage += magicdamage;
  1007. Totalmagicdamage = Math.round(Totalmagicdamage / 1.1);
  1008. var totalh = (stage.pole.obj[defender]['nownumber'] - 1) * stage.pole.obj[defender]['maxhealth'] + stage.pole.obj[defender]['nowhealth'];
  1009. var kills = Math.floor(Math.min(magicdamage, totalh) / stage.pole.obj[defender]['maxhealth']);
  1010. var nowhealth = stage.pole.obj[defender]['nowhealth'] - (Math.min(magicdamage, totalh) - kills * stage.pole.obj[defender]['maxhealth']);
  1011. if (nowhealth <= 0) kills++;
  1012. Totalmagickills += kills;
  1013. };
  1014. }
  1015. // -----------------------------------
  1016.  
  1017. // Функция рельсы гвд с поправкой на выбор клеток юзером
  1018. function magshot(x1, y1, xr, yr) {
  1019. var x2 = xr;
  1020. var y2 = yr;
  1021. var dx = Math.abs(x1 - x2);
  1022. var dy = Math.abs(y1 - y2);
  1023. var skip = false;
  1024. if (x1 < x2) {
  1025. var xp = 1;
  1026. } else {
  1027. var xp = -1;
  1028. };
  1029. if (y1 < y2) {
  1030. var yp = 1;
  1031. } else {
  1032. var yp = -1;
  1033. };
  1034. if (dx > dy) {
  1035. if (x1 > x2) {
  1036. var x = -5;
  1037. } else {
  1038. var x = defxn + 3 - 1;
  1039. };
  1040. var y = (y2 - y1) / (x2 - x1) * (x - x1) + y1;
  1041. } else {
  1042. if (y1 > y2) {
  1043. var y = -5;
  1044. } else {
  1045. var y = defyn + 5 + 1;
  1046. };
  1047. var x = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
  1048. };
  1049. x = x1;
  1050. y = y1;
  1051. while ((x > 0) && (y > 0) && (x <= defxn - 2) && (y <= defyn)) {
  1052. if (dx > dy) {
  1053. x += xp;
  1054. y = (y2 - y1) / (x2 - x1) * (x - x1) + y1;
  1055. } else {
  1056. y += yp;
  1057. x = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
  1058. };
  1059. let shot_coords = []
  1060. if ((Math.round(x) > 0) && (Math.round(y) > 0) && (Math.round(x) <= defxn - 2) && (Math.round(y) <= defyn)) {
  1061. if (shado[Math.round(x) + Math.round(y) * defxn]) {
  1062. set_visible(shado[Math.round(x) + Math.round(y) * defxn], 1);
  1063. shot_coords.push({ x: Math.round(x), y: Math.round(y) })
  1064. }
  1065. };
  1066. setTimeout(() => {
  1067. for (const coord of shot_coords) {
  1068. set_visible(shado[coord.x + coord.y * defxn], 0);
  1069. }
  1070. }, 4000)
  1071. };
  1072. };
  1073.  
  1074. // Родная функция гвд с поправками на переменную l и модификаторами magic[]
  1075. function attackmonster(attacker, ax, ay, x, y, defender, cre_distance, shootok, koef, inuse) {
  1076. let cre_collection = unsafeWindow.stage.pole.obj
  1077. var mainattack = 1;
  1078. var ax1 = ax;
  1079. var ay1 = ay;
  1080. if (defender == 1000) return 0;
  1081. if (defender <= 0) return 0;
  1082. if (!cre_collection[defender]) return 0;
  1083. if (cre_collection[defender]['hero']) return 0;
  1084. if (cre_collection[defender]['rock']) return 0;
  1085. if (koef == undefined) koef = 1;
  1086. if (inuse == undefined) inuse = '';
  1087. var len = unsafeWindow.wmap2[y * defxn + x];
  1088. if ((cre_collection[attacker].x == x) && (cre_collection[attacker].y == y)) len = spd;
  1089. shootok = 1;
  1090.  
  1091. function getAdjacentAndDiagonalCoords(x, y) {
  1092. const adjacentAndDiagonalCoords = [];
  1093. adjacentAndDiagonalCoords.push([x + 1, y]);
  1094. adjacentAndDiagonalCoords.push([x - 1, y]);
  1095. adjacentAndDiagonalCoords.push([x, y + 1]);
  1096. adjacentAndDiagonalCoords.push([x, y - 1]);
  1097. adjacentAndDiagonalCoords.push([x + 1, y + 1]);
  1098. adjacentAndDiagonalCoords.push([x - 1, y + 1]);
  1099. adjacentAndDiagonalCoords.push([x + 1, y - 1]);
  1100. adjacentAndDiagonalCoords.push([x - 1, y - 1]);
  1101. return adjacentAndDiagonalCoords;
  1102. }
  1103.  
  1104. if (cre_collection[attacker].shots === 0) {
  1105. shootok = 0
  1106. } else {
  1107. let attacker_adjacent_coords = getAdjacentAndDiagonalCoords(stage.pole.obj[attacker].x, stage.pole.obj[attacker].y)
  1108. let enemies_list = Object.values(stage.pole.obj).filter(creature => creature.side != stage.pole.obj[attacker].side)
  1109. enemies_list.forEach(enemy => {
  1110. attacker_adjacent_coords.forEach(coord => {
  1111. if (coord[0] == enemy.x && coord[1] == enemy.y && ![0, -1].includes(enemy.nownumber)) shootok = 0
  1112. })
  1113. })
  1114. }
  1115. if (cre_collection[attacker]['big']) {
  1116. if (ax > x) {
  1117. x++;
  1118. };
  1119. if (ay > y) {
  1120. y++;
  1121. };
  1122. };
  1123. if (cre_collection[attacker]['bigx']) {
  1124. if (ax > x) {
  1125. x++;
  1126. };
  1127. };
  1128. if (cre_collection[attacker]['bigy']) {
  1129. if (ay > y) {
  1130. y++;
  1131. };
  1132. };
  1133. var spd = Math.max(0, Math.round((cre_collection[attacker].speed + cre_collection[attacker]['ragespeed'] + cre_collection[attacker]['speedaddon']) * cre_collection[attacker].speedmodifier));
  1134. if (unsafeWindow.magic[attacker]['ent']) {
  1135. spd = 0;
  1136. };
  1137. var movelen = spd - len;
  1138. unsafeWindow.attacker_c = attacker;
  1139. unsafeWindow.ax_c = ax;
  1140. unsafeWindow.ay_c = ay;
  1141. unsafeWindow.x_c = x;
  1142. unsafeWindow.y_c = y;
  1143. unsafeWindow.defender_c = defender;
  1144. unsafeWindow.shootok_c = shootok;
  1145. if ((x == 0) && (y == 0)) {
  1146. x = cre_collection[attacker]['x'];
  1147. y = cre_collection[attacker]['y'];
  1148. };
  1149. if ((defender > 0) && (cre_collection[defender]['big'])) {
  1150. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  1151. ax++;
  1152. };
  1153. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  1154. ay++;
  1155. };
  1156. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  1157. ax--;
  1158. };
  1159. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  1160. ay--;
  1161. };
  1162. };
  1163. if ((defender > 0) && (cre_collection[defender]['bigx'])) {
  1164. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  1165. ax++;
  1166. };
  1167. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  1168. ax--;
  1169. };
  1170. };
  1171. if ((defender > 0) && (cre_collection[defender]['bigy'])) {
  1172. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  1173. ay++;
  1174. };
  1175. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  1176. ay--;
  1177. };
  1178. };
  1179. let dx = x - ax;
  1180. let dy = y - ay;
  1181. l = dx * dx + dy * dy;
  1182. if (movelen == undefined) movelen = 0;
  1183. if (cre_distance !== "") {
  1184. movelen = cre_distance
  1185. l = Math.round(cre_distance * cre_distance)
  1186. if (l > 2) shootok = 1
  1187. else shootok = 0
  1188. if (cre_collection[attacker].shots === 0) shootok = 0
  1189. }
  1190. unsafeWindow.PhysicalModifiers = 1;
  1191. unsafeWindow.PhysicalModifiers *= koef;
  1192. if (cre_collection[attacker]['shadowattack']) l = 0;
  1193.  
  1194. var hera = 0;
  1195. var herd = 0;
  1196. len = unsafeWindow.stage.pole.obj_array.length;
  1197. for (var k1 = 0; k1 < len; k1++) {
  1198. unsafeWindow.k = unsafeWindow.stage.pole.obj_array[k1];
  1199.  
  1200. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[attacker].owner)) hera = unsafeWindow.k;
  1201. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[defender].owner)) herd = unsafeWindow.k;
  1202. };
  1203. if ((cre_collection[defender]['pirate']) && ((unsafeWindow.magic[defender]['sea']) || (unsafeWindow.gtype == 125) || (unsafeWindow.gtype == 126) || (unsafeWindow.gtype == 133))) {
  1204. unsafeWindow.PhysicalModifiers *= 0.85;
  1205. };
  1206. if (cre_collection[defender]['deadflesh']) {
  1207. unsafeWindow.PhysicalModifiers *= 0.8;
  1208. };
  1209. if (cre_collection[defender]['immaterial']) {
  1210. unsafeWindow.PhysicalModifiers *= 0.65;
  1211. };
  1212. if ((cre_collection[attacker]['oppressionofweak']) && (cre_collection[defender]['level'] == 1)) {
  1213. unsafeWindow.PhysicalModifiers *= 1.5;
  1214. };
  1215. if ((cre_collection[attacker]['fearofstrong']) && (cre_collection[defender]['level'] == 7)) {
  1216. unsafeWindow.PhysicalModifiers *= 0.5;
  1217. };
  1218. if ((hera > 0) && (unsafeWindow.magic[hera]['bna'])) {
  1219. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[hera]['bna']['effect'] / 100);
  1220. if ((cre_collection[defender]['mechanical']) && (unsafeWindow.magic[hera]['MEC'])) {
  1221. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['MEC']['effect'] / 100;
  1222. };
  1223. if ((cre_collection[attacker]['mechanical']) && (unsafeWindow.magic[hera]['mch'])) {
  1224. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['mch']['effect'] / 100;
  1225. };
  1226. };
  1227. if ((cre_collection[defender]['building']) && (!cre_collection[attacker]['siegewalls'])) {
  1228. unsafeWindow.PhysicalModifiers *= 0.05;
  1229. };
  1230. if ((defender > 0) && (cre_collection[attacker]['cruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  1231. unsafeWindow.PhysicalModifiers *= 1.15;
  1232. };
  1233. if ((defender > 0) && (cre_collection[attacker]['morecruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  1234. unsafeWindow.PhysicalModifiers *= 1.3;
  1235. };
  1236. if ((cre_collection[attacker]['giantkiller']) && (cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 2;
  1237. if ((cre_collection[attacker]['pygmykiller']) && (!cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 1.33;
  1238. if (cre_collection[attacker]['stormstrike']) unsafeWindow.PhysicalModifiers *= 2;
  1239. if ((cre_collection[attacker]['undeadkiller']) && (cre_collection[defender]['undead'])) unsafeWindow.PhysicalModifiers *= 1.5;
  1240. if ((cre_collection[attacker]['pirate']) && (unsafeWindow.magic[defender]['blb'])) unsafeWindow.PhysicalModifiers *= 1.5;
  1241. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.magic[attacker]['zat'])) {
  1242. unsafeWindow.PhysicalModifiers *= 1.15;
  1243. };
  1244. if ((herd > 0) && (unsafeWindow.magic[herd]['bnd'])) {
  1245. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers / (1 + unsafeWindow.magic[herd]['bnd']['effect'] / 100);
  1246. };
  1247. if ((herd > 0) && (unsafeWindow.magic[herd]['fld'])) {
  1248. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[herd]['fld']['effect'] / 100);
  1249. };
  1250. if ((herd > 0) && (unsafeWindow.magic[herd]['rcd']) && (monster_race[cre_collection[attacker]['id']] == unsafeWindow.magic[herd]['rcd']['effect'])) {
  1251. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.93;
  1252. };
  1253. if (unsafeWindow.magic[attacker]['prp']) {
  1254. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[attacker]['prp']['effect'] / 100);
  1255. };
  1256. if (unsafeWindow.magic[defender]['sta']) {
  1257. unsafeWindow.PhysicalModifiers *= 0.5;
  1258. };
  1259. if ((unsafeWindow.magic[attacker]['chd']) && (cre_collection[unsafeWindow.magic[attacker]['chd']['effect']]['nownumber'] > 0) && (unsafeWindow.magic[attacker]['chd']['effect'] != defender)) {
  1260. unsafeWindow.PhysicalModifiers *= 0.55;
  1261. };
  1262. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.checkmembrane(defender);
  1263. if (!cre_collection[attacker]['hero']) {
  1264. if ((l <= 2 || shootok === 0) && (cre_collection[attacker]['shooter']) && (!cre_collection[attacker]['nopenalty']) && (!cre_collection[attacker]['warmachine'])) {
  1265. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1266. };
  1267. if ((l > 2) && (cre_collection[attacker]['rangepenalty'])) {
  1268. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1269. };
  1270. unsafeWindow.rangemod = 1;
  1271. if (l > 2 && (shootok !== 0 || cre_collection[attacker].shots !== 0) && (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))))) {
  1272. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1273. unsafeWindow.rangemod = 0.5;
  1274. };
  1275. if (l > 2 && (shootok !== 0 || cre_collection[attacker].shots !== 0) && (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))) {
  1276. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1277. unsafeWindow.rangemod *= 0.5;
  1278. };
  1279. };
  1280. var _PERK_ARCHERY = 11;
  1281. var _PERK_EVASION = 22;
  1282. if ((defender > 0) && ((((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1) || cre_collection[attacker].shots == 0) && (!cre_collection[attacker]['ballista']) && (inuse != 'ssh') && (inuse != 'mga') && (inuse != 'dcd') && (inuse != 'chs') && (!cre_collection[attacker]['hero'])) || (inuse == 'brs') || (inuse == 'cpt'))) {
  1283. if (cre_collection[defender]['dodge'])
  1284. unsafeWindow.PhysicalModifiers *= 0.5;
  1285. if (cre_collection[defender]['brittle'])
  1286. unsafeWindow.PhysicalModifiers *= 1.25;
  1287. };
  1288. if ((shootok === 1) && (!cre_collection[attacker]['hero']) && (cre_collection[attacker]['shooter'])) {
  1289. if (unsafeWindow.isperk(attacker, _PERK_ARCHERY)) unsafeWindow.PhysicalModifiers *= 1.2;
  1290. if (unsafeWindow.isperk(defender, _PERK_EVASION)) unsafeWindow.PhysicalModifiers *= 0.8;
  1291. if ((!cre_collection[defender]['lshield']) && (unsafeWindow.stage.pole.shieldother(defender))) {
  1292. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  1293. };
  1294. if ((cre_collection[defender]['lshield']) || (cre_collection[defender]['hollowbones'])) {
  1295. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1296. };
  1297. if (cre_collection[defender]['diamondarmor']) {
  1298. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.1;
  1299. };
  1300. if (cre_collection[defender]['shielded']) {
  1301. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  1302. };
  1303. if (cre_collection[defender]['unprotectedtarget']) {
  1304. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 1.25;
  1305. };
  1306. if (unsafeWindow.magic[defender]['dfm']) {
  1307. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[defender]['dfm']['effect'] / 100);
  1308. };
  1309. if (unsafeWindow.magic[attacker]['cnf']) {
  1310. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[attacker]['cnf']['effect'] / 100);
  1311. };
  1312.  
  1313. if (hera > 0) {
  1314. if (unsafeWindow.magic[hera]['sat']) {
  1315. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[hera]['sat']['effect']) / 100;
  1316. };
  1317. };
  1318. };
  1319. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_BLESS))) {
  1320. unsafeWindow.PhysicalModifiers *= 1.04;
  1321. };
  1322. let o = cre_collection[attacker]['owner'];
  1323. if (unsafeWindow.magic[defender]['mf' + o]) {
  1324. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[defender]['mf' + o]['effect'] / 100;
  1325. };
  1326. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_FERVOR))) {
  1327. unsafeWindow.PhysicalModifiers *= 1.03;
  1328. };
  1329. if (hera > 0) {
  1330. var h = hera;
  1331. if ((unsafeWindow.magic[h]['nut']) && ((plid2 == -2) || (ohotnik_set_neutral()))) {
  1332. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['nut']['effect']) / 100;
  1333. };
  1334. if ((unsafeWindow.magic[h]['mle']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1) || cre_collection[attacker].shots == 0)) {
  1335. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['mle']['effect']) / 100;
  1336. };
  1337. if (unsafeWindow.magic[attacker]['fbd']) {
  1338. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + Math.floor(unsafeWindow.magic[attacker]['fbd']['effect'] / 10)) / 100;
  1339. };
  1340. };
  1341. let leap_atk_bonus, leap_distance = 0;
  1342.  
  1343. if (cre_collection[attacker].leap && l >= 4) {
  1344. leap_distance = cre_distance ? cre_distance : Math.min((movelen - 1) * 2, Math.round(Math.sqrt(l)));
  1345. leap_atk_bonus = cre_collection[attacker].attack * (1 + leap_distance * 0.1) - cre_collection[attacker].attack
  1346. cre_collection[attacker]['attackaddon'] += leap_atk_bonus
  1347. }
  1348. unsafeWindow.monatt = cre_collection[attacker]['attack'] + cre_collection[attacker]['attackaddon'] + cre_collection[attacker]['rageattack'];
  1349. if ((defender > 0) && (cre_collection[attacker]['giantslayer']) && (cre_collection[defender]['big'])) unsafeWindow.monatt += 4;
  1350. if ((!cre_collection[attacker]['undead']) && (!cre_collection[attacker]['hero']) && (!cre_collection[attacker]['perseverance'])) {
  1351. unsafeWindow.frig2 = false;
  1352. unsafeWindow.i = attacker;
  1353. var bigx = cre_collection[i]['big'];
  1354. var bigy = cre_collection[i]['big'];
  1355. if (cre_collection[i]['bigx']) bigx = 1;
  1356. if (cre_collection[i]['bigy']) bigy = 1;
  1357. unsafeWindow.xd = cre_collection[i]['x'];
  1358. unsafeWindow.yd = cre_collection[i]['y'];
  1359. for (var xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  1360. for (var yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  1361. 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)) {
  1362. unsafeWindow.monatt -= 4;
  1363. unsafeWindow.frig2 = true;
  1364. };
  1365. };
  1366. };
  1367. };
  1368.  
  1369. if ((unsafeWindow.magic[attacker]['bsr']) || (unsafeWindow.magic[attacker]['rof'])) {
  1370. unsafeWindow.monatt += Math.floor((cre_collection[attacker]['defence'] + cre_collection[attacker]['defenceaddon'] + cre_collection[attacker]['ragedefence']) * cre_collection[attacker]['defencemodifier']);
  1371. };
  1372. if (herd > 0) {
  1373. h = herd;
  1374. if ((unsafeWindow.magic[h]['mld']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1) || cre_collection[attacker].shots == 0)) {
  1375. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['mld']['effect']) / 100;
  1376. };
  1377. if ((unsafeWindow.magic[h]['_ia']) && (!cre_collection[attacker]['perseverance'])) {
  1378. unsafeWindow.monatt *= (1 - unsafeWindow.magic[h]['_ia']['effect'] / 100);
  1379. };
  1380. if ((!cre_collection[attacker]['hero']) && (cre_collection[attacker].shooter) && (cre_collection[attacker].shots != 0) && (unsafeWindow.magic[h]['msk']) && shootok == 1) {
  1381. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['msk']['effect']) / 100;
  1382. };
  1383. };
  1384. unsafeWindow.defadd = 0;
  1385. if (cre_collection[defender]['agility']) {
  1386. if (!unsafeWindow.magic[defender]['agl']) unsafeWindow.defadd = cre_collection[defender]['speed'] * 2;
  1387. };
  1388. if ((cre_collection[defender]['spirit']) && (!unsafeWindow.magic[defender]['spi'])) {
  1389. unsafeWindow.PhysicalModifiers *= 0.5;
  1390. };
  1391. if ((cre_collection[attacker]['rageagainsttheliving']) && (cre_collection[defender]['alive'])) {
  1392. unsafeWindow.PhysicalModifiers *= 1.3;
  1393. };
  1394. if ((cre_collection[defender]['defensivestance']) && (!unsafeWindow.magic[defender]['mvd'])) {
  1395. unsafeWindow.defadd += 5;
  1396. };
  1397. if ((!cre_collection[defender]['undead']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor'])) {
  1398. unsafeWindow.frig2 = false;
  1399. unsafeWindow.i = defender;
  1400. bigx = cre_collection[i]['big'];
  1401. bigy = cre_collection[i]['big'];
  1402. if (cre_collection[i]['bigx']) bigx = 1;
  1403. if (cre_collection[i]['bigy']) bigy = 1;
  1404. unsafeWindow.xd = cre_collection[i]['x'];
  1405. unsafeWindow.yd = cre_collection[i]['y'];
  1406. for (let xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  1407. for (let yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  1408. 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)) {
  1409. unsafeWindow.defadd -= 4;
  1410. unsafeWindow.frig2 = true;
  1411. };
  1412. };
  1413. };
  1414. };
  1415. if ((attacker > 0) && (cre_collection[defender]['giantslayer']) && (cre_collection[attacker]['big'])) unsafeWindow.defadd += 4;
  1416. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + unsafeWindow.defadd + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  1417. if (unsafeWindow.magic[defender]['bsr']) {
  1418. unsafeWindow.mondef = 0;
  1419. };
  1420.  
  1421. if ((cre_collection[attacker]['preciseshot']) && (l > 2) && (l <= 9) && (unsafeWindow.rangemod >= 1)) {
  1422. unsafeWindow.mondef = 0;
  1423. };
  1424. if ((cre_collection[attacker]['ignoredefence'])) {
  1425. unsafeWindow.mondef *= (1 - cre_collection[attacker]['ignoredefence'] / 100);
  1426. };
  1427. if (cre_collection[attacker]['crushingleadership']) {
  1428. var morale_delta = unsafeWindow.stage.pole.getmorale(attacker) - unsafeWindow.stage.pole.getmorale(defender);
  1429. if (morale_delta > 0) {
  1430. unsafeWindow.mondef *= Math.max(0, 1 - morale_delta / 10);
  1431. };
  1432. };
  1433. if (cre_collection[attacker]['sacredweapon']) {
  1434. var dark_count = get_dark_count(defender);
  1435. if (dark_count > 0) {
  1436. unsafeWindow.mondef *= Math.max(0, 1 - 0.15 * dark_count);
  1437. };
  1438. };
  1439. if (unsafeWindow.isperk(attacker, _PERK_PIERCING_LUCK)) {
  1440. unsafeWindow.mondef *= 1 - Math.max(0, 0.025 * (cre_collection[attacker]['luck'] + cre_collection[attacker]['luckaddon']));
  1441. };
  1442. if ((cre_collection[defender]['ignoreattack'])) {
  1443. unsafeWindow.monatt *= (1 - cre_collection[defender]['ignoreattack'] / 100);
  1444. };
  1445. if ((cre_collection[attacker]['ridercharge']) && (movelen > 0)) {
  1446. unsafeWindow.mondef = unsafeWindow.mondef * (5 - movelen) / 5;
  1447. };
  1448. if ((cre_collection[attacker]['forcearrow']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  1449. unsafeWindow.mondef *= 0.8;
  1450. };
  1451. if ((cre_collection[attacker]['armorpiercing']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  1452. unsafeWindow.mondef *= 0.5;
  1453. };
  1454. if (cre_collection[defender]['shroudofdarkness']) {
  1455. unsafeWindow.PhysicalModifiers *= Math.max(0, 1 - 0.15 * get_dark_count(defender));
  1456. };
  1457. if (cre_collection[attacker]['tasteofdarkness']) {
  1458. unsafeWindow.PhysicalModifiers *= 1 + get_dark_count(defender) * 0.12;
  1459. };
  1460. if ((cre_collection[attacker]['jousting']) && (movelen > 0)) {
  1461. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.05 * movelen);
  1462. };
  1463. if (((cre_collection[attacker]['blindingcharge']) || (cre_collection[attacker]['charge'])) && (movelen > 0)) {
  1464. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.1 * movelen);
  1465. };
  1466. if ((cre_collection[defender]['shieldwall']) && (movelen > 0)) {
  1467. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * Math.max(0.1, 1 - 0.1 * movelen);
  1468. };
  1469. if ((unsafeWindow.magic[defender]['enc']) && (unsafeWindow.magic[defender]['enc']['effect'] == 1)) {
  1470. unsafeWindow.PhysicalModifiers *= 0.5;
  1471. };
  1472. if ((cre_collection[attacker]['safeposition']) && (movelen == 0)) {
  1473. unsafeWindow.PhysicalModifiers *= 1.5;
  1474. };
  1475. if ((cre_collection[attacker]['agilesteed']) && (movelen > 0)) {
  1476. unsafeWindow.PhysicalModifiers *= 1 - 0.05 * movelen;
  1477. };
  1478. if (unsafeWindow.mondef < 0) {
  1479. unsafeWindow.mondef = 0;
  1480. };
  1481.  
  1482. unsafeWindow.air = 0;
  1483. unsafeWindow.fire = 0;
  1484. unsafeWindow.water = 0;
  1485. unsafeWindow.earth = 0;
  1486. if ((hera > 0) && (!cre_collection[attacker]['taran'])) {
  1487. h = hera;
  1488. if (unsafeWindow.magic[h]['_id']) {
  1489. unsafeWindow.mondef *= (1 - unsafeWindow.magic[h]['_id']['effect'] / 100);
  1490. };
  1491. if (unsafeWindow.magic[h]['_aa']) {
  1492. unsafeWindow.air = unsafeWindow.magic[h]['_aa']['effect'] / 100;
  1493. };
  1494. if (unsafeWindow.magic[h]['_af']) {
  1495. unsafeWindow.fire = unsafeWindow.magic[h]['_af']['effect'] / 100;
  1496. };
  1497. if (unsafeWindow.magic[h]['_aw']) {
  1498. unsafeWindow.water = unsafeWindow.magic[h]['_aw']['effect'] / 100;
  1499. };
  1500. if (unsafeWindow.magic[h]['_ae']) {
  1501. unsafeWindow.earth = unsafeWindow.magic[h]['_ae']['effect'] / 100;
  1502. };
  1503. };
  1504. if ((cre_collection[defender]['armoured']) || (cre_collection[defender]['organicarmor'])) {
  1505. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  1506. };
  1507. if (unsafeWindow.monatt < 0) {
  1508. unsafeWindow.monatt = 0;
  1509. };
  1510. if (unsafeWindow.monatt > unsafeWindow.mondef) {
  1511. unsafeWindow.AttackDefenseModifier = 1 + (unsafeWindow.monatt - unsafeWindow.mondef) * 0.05;
  1512. } else {
  1513. unsafeWindow.AttackDefenseModifier = 1 / (1 + (unsafeWindow.mondef - unsafeWindow.monatt) * 0.05);
  1514. };
  1515. if (cre_collection[attacker]['hero']) {
  1516. unsafeWindow.AttackDefenseModifier = 1;
  1517. };
  1518. var _PERK_ATTACK1 = 8;
  1519. var _PERK_ATTACK2 = 9;
  1520. var _PERK_ATTACK3 = 10;
  1521. var _PERK_DEFENSE1 = 19;
  1522. var _PERK_DEFENSE2 = 20;
  1523. var _PERK_DEFENSE3 = 21;
  1524.  
  1525. if ((!cre_collection[attacker]['hero']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1))) {
  1526. if (unsafeWindow.isperk(attacker, _PERK_ATTACK3)) {
  1527. unsafeWindow.PhysicalModifiers *= 1.3;
  1528. } else {
  1529. if (unsafeWindow.isperk(attacker, _PERK_ATTACK2)) {
  1530. unsafeWindow.PhysicalModifiers *= 1.2;
  1531. } else
  1532. if (unsafeWindow.isperk(attacker, _PERK_ATTACK1)) unsafeWindow.PhysicalModifiers *= 1.1;
  1533. };
  1534. if (unsafeWindow.isperk(defender, _PERK_DEFENSE3)) {
  1535. unsafeWindow.PhysicalModifiers *= 0.7;
  1536. } else {
  1537. if (unsafeWindow.isperk(defender, _PERK_DEFENSE2)) {
  1538. unsafeWindow.PhysicalModifiers *= 0.8;
  1539. } else {
  1540. if (unsafeWindow.isperk(defender, _PERK_DEFENSE1)) unsafeWindow.PhysicalModifiers *= 0.9;
  1541. };
  1542. };
  1543. };
  1544. if ((cre_collection[attacker]['siegewalls']) && (cre_collection[defender]['stone'])) {
  1545. unsafeWindow.PhysicalModifiers *= 10;
  1546. };
  1547. var _PERK_COLD_STEEL = 14;
  1548. var _PERK_FIERY_WRATH = 101;
  1549. var _PERK_HELLFIRE_AURA = 123;
  1550. var _PERK_RETRIBUTION = 16;
  1551.  
  1552. if (unsafeWindow.isperk(attacker, _PERK_COLD_STEEL)) unsafeWindow.water = 1 - (1 - unsafeWindow.water) * (0.9);
  1553. if (unsafeWindow.isperk(attacker, _PERK_FIERY_WRATH)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.85);
  1554. if (unsafeWindow.isperk(attacker, _PERK_HELLFIRE_AURA)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.95);
  1555.  
  1556. if (unsafeWindow.magic[attacker]['cre']) {
  1557. unsafeWindow.air = 1 - (1 - unsafeWindow.air) * (1 - unsafeWindow.magic[attacker]['cre']['effect'] / 100);
  1558. };
  1559.  
  1560. if (unsafeWindow.isperk(attacker, _PERK_RETRIBUTION)) unsafeWindow.PhysicalModifiers *= (1 + Math.min(Math.max(unsafeWindow.stage.pole.getmorale(attacker, x, y), 0), 5) / 20);
  1561. 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;
  1562. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.magicmod(attacker, defender, unsafeWindow.fire, unsafeWindow.air, unsafeWindow.water, unsafeWindow.earth, 0.1);
  1563. if ((cre_collection[attacker]['bloodfrenzy']) && (unsafeWindow.magic[defender]['fd1'])) {
  1564. unsafeWindow.PhysicalModifiers *= 1.3;
  1565. };
  1566. unsafeWindow.UmelkaModifiers = 1;
  1567.  
  1568. if ((umelka[cre_collection[attacker]['owner']][0] > 0) && (umelka[cre_collection[defender]['owner']][0] > 0)) {
  1569. unsafeWindow.k = umelka[cre_collection[attacker]['owner']][0];
  1570. if ((unsafeWindow.k > 0) && (unsafeWindow.k < 11)) {
  1571. let j = umelka[cre_collection[defender]['owner']][k];
  1572. unsafeWindow.UmelkaModifiers = 1 - j * 0.03;
  1573. };
  1574. };
  1575. unsafeWindow.NumCreatures = cre_collection[attacker]['nownumber'];
  1576. let tsc = 0;
  1577.  
  1578. bigx = cre_collection[defender]['big'];
  1579. bigy = cre_collection[defender]['big'];
  1580. if (cre_collection[defender]['bigx']) bigx = 1;
  1581. if (cre_collection[defender]['bigy']) bigy = 1;
  1582. for (var xs = cre_collection[defender]['x'] - 1; xs <= cre_collection[defender]['x'] + 1 + bigx; xs++) {
  1583. for (var ys = cre_collection[defender]['y'] - 1; ys <= cre_collection[defender]['y'] + 1 + bigy; ys++) {
  1584. 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'])) {
  1585. tsc++;
  1586. };
  1587. };
  1588. };
  1589.  
  1590.  
  1591. unsafeWindow.PhysicalModifiers /= (tsc + 1);
  1592.  
  1593. var minmag = 0;
  1594. var maxmag = 0;
  1595. if ((inuse == 'lep') && (cre_collection[attacker]['crashingleap'])) {
  1596. unsafeWindow.Totalmagicdamage = 0;
  1597. cre_collection[defender]['attacked'] = 1;
  1598. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 4, 'cold', '', 0, 0, 0);
  1599. minmag = unsafeWindow.Totalmagicdamage;
  1600. unsafeWindow.Totalmagicdamage = 0;
  1601. cre_collection[defender]['attacked'] = 1;
  1602. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 6, 'cold', '', 0, 0, 0);
  1603. maxmag = unsafeWindow.Totalmagicdamage;
  1604. };
  1605.  
  1606. 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'];
  1607. 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'];
  1608. h = hera;
  1609. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['BLS']) && (unsafeWindow.magic[h]['BLS']['effect'] > 0)) unsafeWindow.mindam = unsafeWindow.maxdam;
  1610. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['CRS']) && (unsafeWindow.magic[h]['CRS']['effect'] > 0)) unsafeWindow.maxdam = unsafeWindow.mindam;
  1611. if ((cre_collection[attacker]['taran']) && (cre_collection[defender]['stone'])) {
  1612. h = hera;
  1613. unsafeWindow.mindam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 200 * cre_collection[attacker]['mindam']);
  1614. unsafeWindow.maxdam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 400 * cre_collection[attacker]['maxdam']);
  1615. };
  1616. if (cre_collection[attacker]['accuracy']) unsafeWindow.mindam = unsafeWindow.maxdam;
  1617. unsafeWindow.BaseDamage = unsafeWindow.mindam;
  1618. unsafeWindow.PhysicalDamage = unsafeWindow.NumCreatures * unsafeWindow.BaseDamage * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + minmag;
  1619. unsafeWindow.PhysicalDamage2 = unsafeWindow.NumCreatures * unsafeWindow.maxdam * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + maxmag;
  1620. if ((cre_collection[attacker]['deathstrike']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  1621. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage) {
  1622. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage % cre_collection[defender]['maxhealth'];
  1623. };
  1624. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage2) {
  1625. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage2 % cre_collection[defender]['maxhealth'];
  1626. };
  1627. };
  1628.  
  1629. if (cre_collection[attacker]['bladeofslaughter']) {
  1630. unsafeWindow.PhysicalDamage += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  1631. unsafeWindow.PhysicalDamage2 += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  1632. };
  1633. if (unsafeWindow.magic[attacker]['brk']) {
  1634. unsafeWindow.PhysicalDamage *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  1635. unsafeWindow.PhysicalDamage2 *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  1636. };
  1637. if (unsafeWindow.PhysicalDamage < 1) {
  1638. unsafeWindow.PhysicalDamage = 1;
  1639. };
  1640. if (unsafeWindow.PhysicalDamage2 < 1) {
  1641. unsafeWindow.PhysicalDamage2 = 1;
  1642. };
  1643. if ((cre_collection[attacker]['magicattack']) && (unsafeWindow.l > 2) && (unsafeWindow.stage.pole.issomething(defender, 'dampenmagic'))) unsafeWindow.PhysicalDamage = 0;
  1644. if (unsafeWindow.magic[defender]['rag']) {
  1645. unsafeWindow.PhysicalDamage = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage);
  1646. unsafeWindow.PhysicalDamage2 = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage2);
  1647. };
  1648. if ((cre_collection[attacker]['vorpalsword']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  1649. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'];
  1650. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'];
  1651. };
  1652.  
  1653. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage);
  1654. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2);
  1655. if (cre_collection[defender]['pleasureinpain']) {
  1656. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.9);
  1657. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.9);
  1658. };
  1659. if (cre_collection[defender]['raptureinagony']) {
  1660. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.8);
  1661. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.8);
  1662. };
  1663. var totalh = (cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'];
  1664. unsafeWindow.Uronkills = Math.floor(Math.min(unsafeWindow.PhysicalDamage, totalh) / cre_collection[defender]['maxhealth']);
  1665. unsafeWindow.Uronkills2 = Math.floor(Math.min(unsafeWindow.PhysicalDamage2, totalh) / cre_collection[defender]['maxhealth']);
  1666. var nowhealth = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage, totalh) - unsafeWindow.Uronkills * cre_collection[defender]['maxhealth']);
  1667. var nowhealth2 = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage2, totalh) - unsafeWindow.Uronkills2 * cre_collection[defender]['maxhealth']);
  1668. if (nowhealth <= 0) unsafeWindow.Uronkills++;
  1669. if (nowhealth2 <= 0) unsafeWindow.Uronkills2++;
  1670. unsafeWindow.tUronkills += unsafeWindow.Uronkills;
  1671. unsafeWindow.tUronkills2 += unsafeWindow.Uronkills2;
  1672. unsafeWindow.tPhysicalDamage += unsafeWindow.PhysicalDamage;
  1673. unsafeWindow.tPhysicalDamage2 += unsafeWindow.PhysicalDamage2;
  1674. if (![0, 1].includes(leap_distance)) cre_collection[attacker].attackaddon -= leap_atk_bonus;
  1675. let leap_display_distance = ""
  1676. if (leap_atk_bonus) leap_display_distance = cre_distance ? "" : leap_distance;
  1677. return { distance: leap_display_distance, leap_atk_bonus: leap_atk_bonus }
  1678. }
  1679.  
  1680. function get_dmg_info(attacker_obj_index, defender_obj_index) {
  1681. let cre_collection = unsafeWindow.stage.pole.obj
  1682. let attacker = cre_collection[attacker_obj_index]
  1683. let defender = cre_collection[defender_obj_index]
  1684. let dmg_dict = attackmonster(attacker_obj_index, attacker.x, attacker.y, defender.x, defender.y, defender_obj_index, GM_getValue("cre_distance"));
  1685. let min_damage = unsafeWindow.PhysicalDamage
  1686. let max_damage = unsafeWindow.PhysicalDamage2
  1687. let min_killed, max_killed;
  1688. if (min_damage % defender.maxhealth >= defender.nowhealth) min_killed = Math.floor(min_damage / defender.maxhealth) + 1
  1689. else min_killed = Math.floor(min_damage / defender.maxhealth)
  1690. if (max_damage % defender.maxhealth >= defender.nowhealth) max_killed = Math.floor(max_damage / defender.maxhealth) + 1
  1691. else max_killed = Math.floor(max_damage / defender.maxhealth)
  1692. return { min: min_damage, max: max_damage, min_killed: min_killed, max_killed: max_killed, distance: dmg_dict.distance }
  1693. }
  1694.  
  1695. let defender_obj_id = 0
  1696. let selected_id = 0
  1697.  
  1698. function refresh() {
  1699. isOpen = true
  1700. let cre_collection = unsafeWindow.stage.pole.obj;
  1701. if (cre_distance_on) {
  1702. cre_distance_div.style.display = "inline";
  1703. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  1704. }
  1705. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc], "inline")
  1706.  
  1707. refresh_button.innerHTML = "Обновить"
  1708. let cre_list = Object.values(cre_collection);
  1709. cre_list.sort(function(a, b) {
  1710. return a.obj_index - b.obj_index;
  1711. });
  1712. dmg_list_container.innerHTML = "";
  1713. [...select.children].forEach(child => child.remove())
  1714. let found_defender = false
  1715. cre_list.forEach(defender => {
  1716. if (defender.nownumber > 0 && defender.nametxt != "" && defender.side == chosen.side && defender.hero === undefined) {
  1717. let option_id = `cre_no${cre_list.indexOf(defender)}`;
  1718. select.insertAdjacentHTML("beforeend", `<option id = "${option_id}" value = "${defender.obj_index}">${defender.nametxt} [${defender.nownumber}] </option>`)
  1719. if (!found_defender) {
  1720. if (`${defender.obj_index}` == chosen.creature) found_defender = true
  1721. defender_obj_id = defender.obj_index
  1722. selected_id = [...select.children].indexOf(select.lastChild)
  1723. }
  1724. }
  1725. });
  1726.  
  1727. dmg_list_container.insertAdjacentHTML("beforeend", `<div id = "chosen_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  1728. <span>Урон по </span><span style="color:#ffffff; font-size: 110%; font-weight: bold;">${cre_collection[defender_obj_id].nametxt} [${cre_collection[defender_obj_id].nownumber}] :</span>
  1729. </div>`)
  1730. cre_list.forEach(attacker => {
  1731. if (attacker.side == -chosen.side && attacker.nownumber > 0 && attacker.nametxt != "") {
  1732. let dmg = get_dmg_info(attacker.obj_index, defender_obj_id)
  1733. let practical_overall_hp;
  1734. if (cre_collection[defender_obj_id].attack > attacker.defence) {
  1735. practical_overall_hp = attacker.maxhealth * attacker.nownumber / (1 + 0.05 * Math.abs(cre_collection[defender_obj_id].attack - attacker.defence))
  1736. } else {
  1737. practical_overall_hp = attacker.maxhealth * attacker.nownumber * (1 + 0.05 * Math.abs(cre_collection[defender_obj_id].attack - attacker.defence))
  1738. }
  1739. let row_id = `row_no${cre_list.indexOf(attacker)}`
  1740. let koef_string = `(коэф. урона <b>${( ((dmg.max + dmg.min) / 2) / practical_overall_hp ).toFixed(2)}</b>)`;
  1741. 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>`);
  1742. dmg_list_container.insertAdjacentHTML("beforeend", calcHellFireHTML(attacker, cre_collection[defender_obj_id], cre_collection, dmg));
  1743. mag_damage_on && lastturn > 0 && dmg_list_container.insertAdjacentHTML("beforeend", calcMagicHTML(attacker, cre_collection[defender_obj_id], cre_collection, dmg));
  1744. }
  1745. })
  1746. select.options.item(selected_id).selected = true
  1747. }