battle_damage_tooltip

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

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

  1. // ==UserScript==
  2. // @name battle_damage_tooltip
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.5
  5. // @description Скрины с функционалом ниже. 1.) Показывает урон всех стеков одной стороны по одному выбранному стеку второй стороны. 2.) Если навести курсор на 1 существо, нажать 'e' (русская 'у'), сделать то же самое со вторым, то в чате появится урон первого по второму. Доп. выборы и настройка скорости анимации в настройках боя.
  6. // @author Something begins
  7. // @license University of Sugma
  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. // Активация горячих кнопок на Alt, поменять можно в переменной triggerKey
  17. // Выбор биндов горячих кнопок, редактировать можно снизу, спец символы копировать из списка keyboardKeycodes на 23 строке
  18.  
  19. // посмотреть урон
  20. const seeDamage = "E";
  21. // посмотреть рельсу
  22. const seeMagShot = "U"
  23. // кнопка, зажав которую, становятся активны кнопки ниже
  24. const triggerKey = "alt";
  25. // автобой
  26. const autoBattle = "A";
  27. // вкл/выкл кастом скорость боя
  28. const toggleSpeed = "S";
  29. // авто расстановка
  30. const autoPlacement = "R";
  31. // кнопка назад
  32. const backToGame = "Z";
  33. // начать бой
  34. const startBattle = "B";
  35.  
  36. const keyboardKeycodes = {
  37. "backspace": 8,
  38. "tab": 9,
  39. "enter": 13,
  40. "shift": 16,
  41. "ctrl": 17,
  42. "alt": 18,
  43. "pause": 19,
  44. "capslock": 20,
  45. "escape": 27,
  46. "space": 32,
  47. "pageup": 33,
  48. "pagedown": 34,
  49. "end": 35,
  50. "home": 36,
  51. "leftarrow": 37,
  52. "uparrow": 38,
  53. "rightarrow": 39,
  54. "downarrow": 40,
  55. "insert": 45,
  56. "delete": 46,
  57. "0": 48,
  58. "1": 49,
  59. "2": 50,
  60. "3": 51,
  61. "4": 52,
  62. "5": 53,
  63. "6": 54,
  64. "7": 55,
  65. "8": 56,
  66. "9": 57,
  67. "a": 65,
  68. "b": 66,
  69. "c": 67,
  70. "d": 68,
  71. "e": 69,
  72. "f": 70,
  73. "g": 71,
  74. "h": 72,
  75. "i": 73,
  76. "j": 74,
  77. "k": 75,
  78. "l": 76,
  79. "m": 77,
  80. "n": 78,
  81. "o": 79,
  82. "p": 80,
  83. "q": 81,
  84. "r": 82,
  85. "s": 83,
  86. "t": 84,
  87. "u": 85,
  88. "v": 86,
  89. "w": 87,
  90. "x": 88,
  91. "y": 89,
  92. "z": 90,
  93. "leftwindowkey": 91,
  94. "rightwindowkey": 92,
  95. "selectkey": 93,
  96. "numpad0": 96,
  97. "numpad1": 97,
  98. "numpad2": 98,
  99. "numpad3": 99,
  100. "numpad4": 100,
  101. "numpad5": 101,
  102. "numpad6": 102,
  103. "numpad7": 103,
  104. "numpad8": 104,
  105. "numpad9": 105,
  106. "multiply": 106,
  107. "add": 107,
  108. "subtract": 109,
  109. "decimalpoint": 110,
  110. "divide": 111,
  111. "f1": 112,
  112. "f2": 113,
  113. "f3": 114,
  114. "f4": 115,
  115. "f5": 116,
  116. "f6": 117,
  117. "f7": 118,
  118. "f8": 119,
  119. "f9": 120,
  120. "f10": 121,
  121. "f11": 122,
  122. "f12": 123,
  123. "numlock": 144,
  124. "scrolllock": 145,
  125. "semicolon": 186,
  126. "equal": 187,
  127. "comma": 188,
  128. "dash": 189,
  129. "period": 190,
  130. "forwardslash": 191,
  131. "graveaccent": 192,
  132. "openbracket": 219,
  133. "backslash": 220,
  134. "closebracket": 221,
  135. "singlequote": 222
  136. };
  137.  
  138. const pressedKeys = new Set();
  139.  
  140. function handleKeyDown(event) {
  141. pressedKeys.add(event.keyCode);
  142. }
  143.  
  144. function handleKeyUp(event) {
  145. pressedKeys.delete(event.keyCode);
  146. }
  147.  
  148. document.addEventListener("keydown", handleKeyDown);
  149. document.addEventListener("keyup", handleKeyUp);
  150.  
  151. // Странные способы в некоторых местах обусловлены конфликтом со скриптом battleHelper от omne
  152. let outer_chat = document.getElementById("chat_format");
  153. let atLaunch = true;
  154. const physCalcColor = "#141736";
  155. const magCalcColor = "#150f1c";
  156. const calcHellFireColor = "rgba(255,0,0,0.1)";
  157. const inputHTML = `<input type="text" id="uprava_filter_input" placeholder="Ник для управы">`;
  158. outer_chat.insertAdjacentHTML("beforeend", `
  159. <div id="cre_distance_div" style="display: none"></div>
  160. <div id="individual_calc"></div>
  161. <div id="mag_calc"></div>
  162. <div id="dmg_list_container"></div>
  163. <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>
  164. <select style="display : none; background-color: #333; color: white; margin: 10px" id="choose_cre"></select>
  165. <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>
  166. <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> `)
  167.  
  168. let last_individual_calc = {}
  169. let isOpen = false
  170. let ini_weight = 10;
  171. let chosen = { side: 1, creature: "Высшие вампиры", afterSideSwitchCre: { "-1": "", "1": "" } }
  172. let chat = document.getElementById("chat_inside");
  173. let select = document.getElementById("choose_cre")
  174. let refresh_button = document.getElementById("dmg_list_refresh")
  175. let side_button = document.getElementById("change_side")
  176. let collapse_button = document.getElementById("collapse")
  177. let individual_calc = document.querySelector("#individual_calc")
  178. let cre_distance_div = document.querySelector("#cre_distance_div")
  179. const settings_panel = document.querySelector("#webgl_settings_whole")
  180. let dmg_list_container = document.querySelector("#dmg_list_container")
  181. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`;
  182.  
  183. // ========= utils ============
  184. function get_GM_value_if_exists(GM_key, default_value) {
  185. const GM_value = GM_getValue(GM_key)
  186. return GM_value != undefined ? GM_value : default_value;
  187. }
  188.  
  189. function triggerMouseUpEvent(element) {
  190. let clickEvent = document.createEvent('MouseEvents');
  191. clickEvent.initEvent("mouseup", true, true);
  192. element.dispatchEvent(clickEvent);
  193. }
  194.  
  195. function getCurrentBattleSpeed() {
  196. for (let i = 1; i <= 3; i++) {
  197. let div = document.querySelector(`#speed${i}_button`)
  198. if (div.style.display === 'none') continue
  199. if (i === 1) return 2
  200. else if (i === 3) return 1
  201. else return 4
  202. }
  203. }
  204.  
  205. function setBattleSpeed(value) {
  206. if (value === 0) return value
  207. else if (value < 1) {
  208. unsafeWindow.timer_interval = Math.abs(value) * 20;
  209. return value
  210. }
  211. unsafeWindow.animspeed_def = unsafeWindow.animspeed = value
  212. unsafeWindow.animspeed_init = unsafeWindow.animspeed > 4 ? 0.5 : 2;
  213. unsafeWindow.timer_interval = Math.abs(value - 20);
  214. !unsafeWindow.timer_interval && unsafeWindow.timer_interval++;
  215. return value
  216. }
  217. function countOccurrences(arr, element) {
  218. return arr.reduce((acc, curr) => (curr === element ? acc + 1 : acc), 0);
  219. }
  220. function insertInput() {
  221. const parent = document.querySelector("#bcontrol_users");
  222. if (parent.querySelector("#uprava_filter_input")) return;
  223. parent.insertAdjacentHTML("afterbegin", inputHTML);
  224. }
  225. function upravaEvent(event){
  226. const parent = document.querySelector("#bcontrol_users");
  227. for (const child of parent.children) {
  228. if (child.tagName === "INPUT") continue;
  229. if (event.target.value === "") {
  230. child.classList.remove("hidden");
  231. continue;
  232. }
  233. const relevant = child.querySelector("span").textContent.toLowerCase().includes(event.target.value.toLowerCase());
  234. if (relevant) {
  235. child.classList.remove("hidden");
  236. } else {
  237. child.classList.add("hidden");
  238. }
  239. }
  240. }
  241. // инфа о гейтах на карте
  242. function initGates() {
  243. const match = document.body.innerHTML.match(/umka\|(.+?)\|/);
  244. if (!match) return;
  245. const umka = match[1];
  246. const factions = [];
  247. for (let i = 1; i < umka.length; i += 14) {
  248. factions.push(umka[i]);
  249. }
  250. const demonsNo = countOccurrences(factions, "7");
  251. if (demonsNo < 1) return;
  252. document.head.insertAdjacentHTML("beforeEnd", `
  253. <style>
  254. #floatingBox {
  255. position: absolute;
  256. background-color: rgba(255, 255, 255, 0.5);
  257. color: white;
  258. padding: 10px;
  259. border-radius: 8px;
  260. pointer-events: none;
  261. white-space: nowrap;
  262. display: none;
  263. }
  264. .line {
  265. font-family: Arial, sans-serif;
  266. font-size: 16px;
  267. margin: 5px 0;
  268. }
  269. </style>
  270. `);
  271. document.body.insertAdjacentHTML("beforeEnd", `
  272. <div id="floatingBox">
  273. <div class="line" id = "gate_name">Гейт [#] </div>
  274. ${demonsNo > 1 ? '<div class="line" id = "gate_owner"> Владелец</div>' : ''}
  275. </div>
  276. `);
  277. const floatingBox = document.getElementById('floatingBox');
  278. document.addEventListener("mousemove", event => {
  279. const [gate_x, gate_y] = [xr_last, yr_last]
  280. if (gate_x > defxn || gate_y > defyn || gate_x < 0 || gate_y < 0) {
  281. floatingBox.style.display = "none";
  282. return;
  283. }
  284. let foundGate = false;
  285. let curGate;
  286. for (const cre of Object.values(stage.pole.obj)) {
  287. if (cre.nownumber !== -1) continue;
  288. if (cre.x !== gate_x || cre.y !== gate_y) continue;
  289. foundGate = true;
  290. curGate = cre;
  291. break;
  292. }
  293. if (!foundGate) {
  294. floatingBox.style.display = "none";
  295. return;
  296. };
  297. floatingBox.style.display = "block";
  298. const mouseX = event.pageX;
  299. const mouseY = event.pageY;
  300. floatingBox.style.left = mouseX + 10 + 'px';
  301. floatingBox.style.top = mouseY + 10 + 'px';
  302. document.querySelector("#gate_name").innerHTML = `${curGate.nametxt} [${curGate.maxnumber}]`;
  303. document.querySelector("#floatingBox").style.color = curGate.get_color();
  304.  
  305. if (demonsNo < 2) return;
  306. const owner = stage.pole.obj[heroes[curGate.owner]]
  307. document.querySelector("#gate_owner").innerHTML = `${owner.nametxt} [${owner.maxhealth}]`
  308. })
  309. }
  310. function calcKilled(dmg, defender) {
  311. let killed;
  312. if (dmg % defender.maxhealth > defender.nowhealth) killed = Math.floor(dmg / defender.maxhealth) + 1
  313. else killed = Math.floor(dmg / defender.maxhealth);
  314. return killed
  315. }
  316.  
  317. function calcHellFireHTML(attacker, defender, cre_collection, physDamage) {
  318. if (!isperk(attacker.obj_index, 7) || attacker.hero === 1) {
  319. return "";
  320. }
  321. const dmg = calcHellFire(attacker, defender, cre_collection);
  322. const minDamage = dmg + physDamage.min;
  323. const maxDamage = dmg + physDamage.max;
  324. const minKilled = calcKilled(minDamage, defender);
  325. const maxKilled = calcKilled(dmg + physDamage.max, defender);
  326. return `<p id="${0}" style=" background-color: ${calcHellFireColor}">
  327. <span style="color:white; font-size: 90%">Адское пламя: </span> <span style = "color:red">${dmg}</span> <span style = "font-size: 80%">урона</span><br>
  328. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${minKilled}-${maxKilled}</b> существ <span style="color:#ffffff">(${minDamage}-${maxDamage})
  329. </p><br>`;
  330. }
  331.  
  332. function calcStormHTML(attacker, defender) {
  333. let koef;
  334. //console.log(attacker);
  335. if (attacker.stormstrike) koef = 0.5;
  336. else if (attacker.flamestrike) koef = 1.2;
  337. else return "";
  338. let xr = defender.x;
  339. let yr = defender.y;
  340. let i = attacker.obj_index;
  341. let dmgMap;
  342. Totalmagicdamage = 0;
  343. Totalmagickills = 0;
  344. var ok = false;
  345. var xx = 0,
  346. yy = 0,
  347. xp = 0,
  348. yp = 0;
  349. mul = 1;
  350. var len = stage.pole.obj_array.length;
  351. for (var k1 = 0; k1 < len; k1++) {
  352. var j = stage.pole.obj_array[k1];
  353. stage.pole.obj[j]['attacked'] = 1;
  354. stage.pole.obj[j]['attacked2'] = 1;
  355. }
  356. var herd = 0;
  357. var hera = 0;
  358. for (var k1 = 0; k1 < len; k1++) {
  359. k = stage.pole.obj_array[k1];
  360. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[mapobj[xr + yr * defxn]].owner)) herd = k;
  361. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[i].owner)) hera = k;
  362. }
  363. let b = 0;
  364. if ((magic[hera]) && (magic[hera]['mle'])) {
  365. b = magic[hera]['mle']['effect'];
  366. magic[hera]['mle']['effect'] = 0;
  367. }
  368. if (magic[herd]) {
  369. let rangedDef;
  370. if (magic[herd]['msk']) rangedDef = magic[herd]['msk']['effect'];
  371. else rangedDef = 0;
  372. if (magic[herd]['mld']) {
  373. let b = magic[herd]['mld']['effect'];
  374. magic[herd]['mld']['effect'] = rangedDef;
  375. dmgMap = get_dmg_info(attacker.obj_index, defender.obj_index, koef);
  376. magic[herd]['mld']['effect'] = b;
  377. } else {
  378. magic[herd]['mld'] = [];
  379. magic[herd]['mld']['effect'] = rangedDef;
  380. dmgMap = get_dmg_info(attacker.obj_index, defender.obj_index, koef);
  381. delete magic[herd]['mld'];
  382. }
  383. } else {
  384. dmgMap = get_dmg_info(attacker.obj_index, defender.obj_index, koef);
  385. }
  386. if (b != 0) {
  387. magic[hera]['mle']['effect'] = b;
  388. }
  389. //console.log(dmgMap);
  390. return `<p id="${0}" style=" background-color: ${calcHellFireColor}">
  391. <span style="color:white; font-size: 90%">Урон абилкой: </span><br>
  392. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${dmgMap.min_killed}-${dmgMap.max_killed}</b> существ <span style="color:#ffffff">(${dmgMap.min}-${dmgMap.max})
  393. </p><br>`;
  394. }
  395.  
  396. function calcMagicHTML(attacker, defender, cre_collection, dmg, inList = false) {
  397. if (!mag_damage_on) return "";
  398. let calcHTML = "";
  399. const disclaimerHTML = `<span class="tooltip"> !!! <span class="tooltiptext" style = "width:3000%; transform: translateX(-30%);"> КБО) это заклинание показывает <br> неправильный урон </span>
  400. </span>`;
  401.  
  402. const incorrectSpellIDs = ["circle_of_winter", "swarm", "stormcaller"];
  403. // если темная сила, то дописать урон с усилком
  404. const isPowered = attacker.hero && unsafeWindow.isperk(attacker.obj_index, 6) ? true : false;
  405. for (let spellID of Object.keys(damageSpells)) {
  406. let additionalInfoHTML = "";
  407. if (attacker[spellID]) {
  408. if (spellID === "calllightning") spellID = "lighting";
  409. const dmg = unsafeWindow.stage.pole.calcmagic_script(attacker.x, attacker.y, defender.x, defender.y, spellID);
  410. if (spellID === "meteor") {
  411. let meteorText = "Целей:<br>";
  412. for (let i = 1; i <= 4; i++) {
  413. let dmg2 = Math.floor(dmg * Math.pow(0.85, i));
  414. let killed2 = calcKilled(dmg2, defender);
  415. const poweredDamage = Math.round(dmg2 * 1.5);
  416. const poweredKilled = calcKilled(poweredDamage, defender);
  417. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  418. meteorText += `[${i+1}]: ${killed2} существ (${dmg2}) ${poweredDamageText}<br>`;
  419. }
  420. additionalInfoHTML = `<span class="tooltip"> +++ <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"}">${meteorText}</span>
  421. </span>`;
  422. }
  423. if (spellID === "chainlighting") {
  424. let chainText = "Цель №<br>";
  425. const penaltyArr = Array(0.5, 0.25, 0.125);
  426. for (let i = 0; i < 3; i++) {
  427. let dmg2 = unsafeWindow.stage.pole.calcmagic_script(attacker.x, attacker.y, defender.x, defender.y, spellID, penaltyArr[i]);
  428. let killed2 = calcKilled(dmg2, defender);
  429. const poweredDamage = Math.round(dmg2 * 1.5);
  430. const poweredKilled = calcKilled(poweredDamage, defender);
  431. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  432. chainText += `${i+2} : ${killed2} существ (${dmg2}) ${poweredDamageText}<br>`;
  433. }
  434. additionalInfoHTML = `<span class="tooltip"> +++ <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"};">${chainText}</span>
  435. </span>`;
  436. }
  437. if (spellID === "poison") {
  438. additionalInfoHTML = `<span class="tooltip"> !!! <span class="tooltiptext" style = "width:1000%; transform: ${isPowered? "translateY(30%);" : "translateX(-60%);"};">Погрешность +-10%</span>
  439. </span>`;
  440. }
  441. let killed = calcKilled(dmg, defender);
  442. const poweredDamage = Math.round(dmg * 1.5);
  443. const poweredKilled = calcKilled(poweredDamage, defender);
  444. const poweredDamageText = isPowered ? `<span style = "font-style:italic; font-size:80%"><br>\t[1.5x] ${poweredKilled} существ (${poweredDamage})<br></span>` : "";
  445. // calcHTML+= `${damageSpells[spellID]} ---> ${dmg} \t (${killed} существ)`;
  446. calcHTML += `<p id="${0}" style=" background-color: ${magCalcColor}">
  447. <span style="color:white; font-size: 90%">${damageSpells[spellID]}: </span><br>
  448. <b style="color:#ffffff; font-size: 120%; text-decoration: underline;">${killed}</b> существ <span style="color:#ffffff">(${dmg}) ${poweredDamageText}</span> ${incorrectSpellIDs.includes(spellID) ? disclaimerHTML : additionalInfoHTML}
  449. </p>`;
  450. }
  451. }
  452. calcHTML += "<br>";
  453. return calcHTML;
  454. }
  455.  
  456. function calcPhysHTML(attacker, defender, dmg, distance_str) {
  457. return ` <div id="individual_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  458. ${distance_str}
  459. <span>Урон <br>
  460. </span>
  461. <span>
  462. <b>${attacker.nametxt}</b> ${attacker.hero === 1 ? "" : ("[" + attacker.nownumber + "]")} по <b>${defender.nametxt}</b> [${defender.nownumber}]: <br>
  463. <br>
  464. </span>
  465. </div>
  466. <p id="${0}" style=" background-color: ${physCalcColor}">
  467. <span style=color:#bfbfbf"></span>
  468. <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>)
  469. </p>
  470. <br>`;
  471. }
  472.  
  473. function individual_calc_innerHTML(atk_obj_index, def_obj_index) {
  474. if (atk_obj_index === undefined || def_obj_index === undefined) return "";
  475. let cre_collection = unsafeWindow.stage.pole.obj;
  476. let attacker = cre_collection[atk_obj_index];
  477. let defender = cre_collection[def_obj_index];
  478. let dmg = get_dmg_info(atk_obj_index, def_obj_index);
  479. let distance_str = dmg.distance === "" ? "" : `<p> Прыжок на <u>${dmg.distance}</u> клеток </p>`;
  480. last_individual_calc.atk_obj_index = atk_obj_index;
  481. last_individual_calc.def_obj_index = def_obj_index;
  482. let calcHTML = calcPhysHTML(attacker, defender, dmg, distance_str) + calcHellFireHTML(attacker, defender, cre_collection, dmg) + calcStormHTML(attacker, defender) + (lastturn > 0 ? calcMagicHTML(attacker, defender, cre_collection, dmg) : "");
  483.  
  484. return calcHTML;
  485. }
  486.  
  487. function paint_coords(x, y, color, timeout = 2077) {
  488. let tile = shado[x + y * defxn]
  489. if (tile == undefined) return
  490. tile.fill(color)
  491. set_visible(tile, 1)
  492.  
  493. setTimeout(() => {
  494. tile.fill(null)
  495. set_visible(tile, 0)
  496. }, timeout)
  497. }
  498. // const observer = new MutationObserver((mutationsList, observer) => {
  499. // for (const mutation of mutationsList) {
  500. // if (mutation.type !== 'childList') return
  501. // for (const addedNode of mutation.addedNodes) {
  502. // if (!(addedNode.classList && addedNode.classList.contains('cont') || ["B", "BR"].includes(addedNode.tagName))) continue
  503. // wrap_battlehelper();
  504. // battlehelper_div.style.display = battleHelper_on ? "inline" : "none";
  505. // }
  506. // }
  507. // });
  508.  
  509. function GM_toggle_boolean(GM_key, boolean) {
  510. boolean = !boolean
  511. GM_setValue(GM_key, boolean);
  512. return boolean
  513. }
  514.  
  515. function set_Display(element_arr, displayProperty) {
  516. element_arr.forEach(element => {
  517. if (element == null) return
  518. element.style.display = displayProperty
  519. })
  520. }
  521.  
  522. function readjust_elements() {
  523. chat = document.getElementById("chat_inside");
  524. select = document.getElementById("choose_cre")
  525. refresh_button = document.getElementById("dmg_list_refresh")
  526. side_button = document.getElementById("change_side")
  527. collapse_button = document.getElementById("collapse")
  528. dmg_list_container = document.querySelector("#dmg_list_container")
  529. individual_calc = document.querySelector("#individual_calc")
  530. cre_distance_div = document.querySelector("#cre_distance_div")
  531. }
  532. // -----------------------------------
  533. // ========= Настройки ============
  534.  
  535. let cre_distance = get_GM_value_if_exists('cre_distance', "")
  536. let cre_distance_on = get_GM_value_if_exists('cre_distance_on', false)
  537. let coeff_on = get_GM_value_if_exists('coeff_on', false)
  538. let animation_speed_on = get_GM_value_if_exists("animation_speed_on", false);
  539. let mag_damage_on = get_GM_value_if_exists("mag_damage_on", true);
  540.  
  541. const new_settings = `
  542. <style>
  543. .tooltip {
  544. position: relative;
  545. display: inline-block;
  546. text-size: 150%;
  547. color: brown;
  548. text-decoration: underline;
  549. }
  550.  
  551. .tooltip .tooltiptext {
  552. visibility: hidden;
  553. position: absolute;
  554. bottom: 100%;
  555. left: 50%;
  556. padding: 5px;
  557. background-color: #555;
  558. color: #fff;
  559. border-radius: 6px;
  560. word-wrap: break-word;
  561. }
  562.  
  563. .tooltip:hover .tooltiptext {
  564. visibility: visible;
  565. }
  566. </style>
  567. <div class="info_row">
  568. <label class="checkbox_container">коэф. урона <span class="tooltip">? <span class="tooltiptext" style = "width: 5000%; transform: translateX(-30%);">отношение урон/хп (т.е. у кого больше всех коэф., с того выгоднее начинать. <br>Работает в списке уронов если нажать на "Открыть" в чате)</span>
  569. </span>
  570. <input type="checkbox" checked="true" id="coeff_on">
  571. <span class="checkbox_checkmark"></span>
  572. </label>
  573. </div>
  574. <div class="info_row">
  575. <label class="checkbox_container">Расстояние между стеками <span class="tooltip">? <span class="tooltiptext transform: translateX(-30%);" style = "width: 5000%;">Расстояние между атакующим и защищающимся стеками. Выбирать расстояние стрелочками в текстовом поле снизу. <br>
  576. Влияет на статус урона стрелка (ближний/дальний урон, кривая/прямая стрела),
  577. разбег и прочие абилки, зависящие от расстояния. <br> Если выставить "Расстояние: 1", то стрелок будет считаться заблокированным.
  578. Если выставить расстояние больше 1,
  579. то стрелок будет считаться не заблокированным (даже если рядом с ним вражеское существо). </span>
  580. </span>
  581. <input type="checkbox" checked="true" id="cre_distance_on">
  582. <span class="checkbox_checkmark"></span>
  583. </label>
  584. <input type="number" style="width: 4%; margin: 2px 2px 2px 80px" id="cre_distance" onkeydown="return false;" value=${cre_distance}>
  585. </div>
  586. <div class="info_row">
  587. <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>
  588. </span>
  589. <input type="checkbox" checked="true" id="animation_speed_on">
  590. <span class="checkbox_checkmark"></span>
  591. </label>
  592. <input type="number" style="width: 5%; margin: 2px 2px 2px 80px" id="anim_speed" onkeydown="return false;" >
  593. </div>
  594. <div class="info_row">
  595. <label class="checkbox_container">Расчет маг. урона <span class="tooltip"> * <span class="tooltiptext" style = "width: 5000%; transform: translateX(-30%);"> Расчет магического урона не работает во время расстановки
  596. </span></span>
  597. <input type="checkbox" checked="true" id="mag_damage_on">
  598. <span class="checkbox_checkmark"></span>
  599. </label>
  600. </div>
  601. `
  602. settings_panel.insertAdjacentHTML("beforeend", new_settings)
  603.  
  604. let settings_interval = setInterval(() => {
  605. if (Object.keys(unsafeWindow.stage.pole.obj).length !== 0) {
  606. initMagicCalc();
  607.  
  608. document.querySelector("#mag_damage_on").checked = mag_damage_on;
  609. document.querySelector("#coeff_on").checked = coeff_on
  610. document.querySelector("#cre_distance_on").checked = cre_distance_on
  611. document.querySelector("#animation_speed_on").checked = animation_speed_on
  612. let spd = get_GM_value_if_exists("anim_speed", getCurrentBattleSpeed())
  613. document.querySelector("#anim_speed").value = spd
  614. if (GM_getValue("animation_speed_on")) setBattleSpeed(spd);
  615. // без таймаута гвд крашится :\
  616. //if (btype === 66) setTimeout(make_ins_but, 1000);
  617. // убрал, чет лагает с этим
  618. if (location.href.includes("&lt")) {
  619. const test = document.querySelector("#pause_button");
  620. if (test.style.display === "none") {
  621. show_button("pause_button");
  622. pause_button_onRelease()
  623. }
  624.  
  625. }
  626. clearInterval(settings_interval)
  627. }
  628. }, 300);
  629. let upravaRoot;
  630. const upravaInterval = setInterval(() => {
  631. upravaRoot = document.querySelector("#win_BattleControl");
  632. if (!upravaRoot) return;
  633. else {
  634. clearInterval(upravaInterval);
  635. upravaRoot.insertAdjacentHTML("afterbegin",
  636. `
  637. <style>
  638. .hidden {
  639. display: none;
  640. }
  641. </style>
  642. `);
  643. insertInput();
  644.  
  645. const observer = new MutationObserver(mutations => {
  646. mutations.forEach(mutation => {
  647. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  648. insertInput();
  649. }
  650. });
  651. });
  652. const config = { childList: true, subtree: true };
  653. observer.observe(upravaRoot, config);
  654. }
  655.  
  656. }, 100);
  657. const distance_counter = document.getElementById("cre_distance");
  658. const anim_speed_counter = document.querySelector("#anim_speed")
  659.  
  660.  
  661. // ========= Event Listeners ============
  662. document.body.addEventListener('input', function(event) {
  663. switch (event.target.id) {
  664. case "cre_distance":
  665. if (distance_counter.value < 1) {
  666. distance_counter.value = 1
  667. return
  668. }
  669. if (!cre_distance_on) return
  670. GM_setValue('cre_distance', distance_counter.value)
  671. if (isOpen) refresh()
  672. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  673. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  674. break;
  675. case "anim_speed":
  676. if (anim_speed_counter.value > 20) {
  677. anim_speed_counter.value = 20
  678. return
  679. }
  680. GM_setValue('anim_speed', anim_speed_counter.value)
  681. if (!animation_speed_on) return
  682. setBattleSpeed(anim_speed_counter.value)
  683. break;
  684. }
  685. });
  686. const anim_speed_input = document.querySelector('#anim_speed')
  687. document.addEventListener('keydown', event => {
  688. if ((document.querySelector("#chattext") === document.activeElement) || (document.querySelector("#chattext_classic") === document.activeElement)) return;
  689.  
  690. const keyCode = parseInt(event.keyCode);
  691. //console.log(keyboardKeycodes[triggerKey.toLowerCase()].toString(), pressedKeys);
  692. if (!pressedKeys.has(keyboardKeycodes[triggerKey.toLowerCase()]) || !Object.values(keyboardKeycodes).includes(keyCode)) return;
  693. //console.log(keyCode, keyboardKeycodes[backToGame.toLocaleLowerCase()], keyboardKeycodes[backToGame.toLocaleLowerCase()] === keyCode);
  694. if (keyCode === keyboardKeycodes[toggleSpeed.toLowerCase()]) {
  695. animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
  696. document.querySelector("#animation_speed_on").checked = animation_speed_on
  697. if (animation_speed_on) {
  698. GM_setValue('anim_speed', anim_speed_counter.value)
  699. setBattleSpeed(anim_speed_counter.value);
  700. } else {
  701. setBattleSpeed(getCurrentBattleSpeed());
  702. }
  703. }
  704. if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
  705. event.preventDefault();
  706. const increment = event.key === 'ArrowUp' ? 1 : -1;
  707. anim_speed_input.value = parseInt(anim_speed_input.value) + increment;
  708. anim_speed_input.dispatchEvent(new Event('input', { bubbles: true }));
  709. }
  710. if (keyCode === keyboardKeycodes[autoBattle.toLowerCase()]) {
  711. fastbut_onRelease2();
  712. }
  713. if (keyCode === keyboardKeycodes[autoPlacement.toLowerCase()]) {
  714. make_ins_but();
  715. }
  716. if (keyCode === keyboardKeycodes[startBattle.toLowerCase()]) {
  717. document.querySelector("#confirm_ins_img") && triggerMouseUpEvent(document.querySelector("#confirm_ins_img"));
  718. }
  719. if (keyCode === keyboardKeycodes[backToGame.toLowerCase()]) {
  720. // document.querySelector("#back_to_game > img") && document.querySelector("#back_to_game > img").click();
  721. if (history.length > 1) {
  722. back_to_game_button_onRelease();
  723. } else {
  724. back_to_home_button_onRelease();
  725. }
  726. }
  727. });
  728. document.body.addEventListener('change', function(event) {
  729. switch (event.target.id) {
  730. case "mag_damage_on":
  731. mag_damage_on = GM_toggle_boolean("mag_damage_on", mag_damage_on);
  732. if (isOpen) refresh();
  733. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  734. break;
  735. case "coeff_on":
  736. coeff_on = GM_toggle_boolean("coeff_on", coeff_on);
  737. if (isOpen) refresh();
  738. break;
  739. case "choose_cre":
  740. chosen.creature = select.value
  741. refresh()
  742. break;
  743. case "cre_distance_on":
  744. cre_distance_on = GM_toggle_boolean("cre_distance_on", cre_distance_on)
  745. cre_distance_on ? GM_setValue('cre_distance', distance_counter.value) : GM_setValue('cre_distance', "")
  746. if (cre_distance_on) {
  747. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  748. cre_distance_div.style.display = "inline"
  749. if (isOpen) refresh()
  750. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  751. } else {
  752. cre_distance_div.innerHTML = ""
  753. }
  754. if (isOpen) refresh()
  755. individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
  756. break;
  757. case "animation_speed_on":
  758. animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
  759. if (animation_speed_on) {
  760. GM_setValue('anim_speed', anim_speed_counter.value)
  761. setBattleSpeed(anim_speed_counter.value);
  762. } else {
  763. setBattleSpeed(getCurrentBattleSpeed());
  764. }
  765. break;
  766. }
  767. });
  768. document.body.addEventListener('click', function(event) {
  769. if (event.target.parentElement && /speed(.)_button/.test(event.target.parentElement.id)) {
  770. setBattleSpeed(getCurrentBattleSpeed());
  771. document.querySelector("#animation_speed_on").checked = false
  772. GM_setValue('animation_speed_on', false)
  773. }
  774. switch (event.target.id) {
  775. case "dmg_list_refresh":
  776. readjust_elements()
  777. refresh()
  778. break
  779. case "change_side":
  780. chosen.afterSideSwitchCre[chosen.side] = chosen.creature
  781. chosen.side = -chosen.side
  782. chosen.creature = chosen.afterSideSwitchCre[chosen.side]
  783. refresh()
  784. break
  785. case "collapse":
  786. readjust_elements()
  787. isOpen = false
  788. refresh_button.innerHTML = "Открыть";
  789. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc, cre_distance_div], "none")
  790. break
  791. // case "confirm_ins_img":
  792. // observer.observe(outer_chat, { childList: true });
  793. // setTimeout(function() {
  794. // observer.disconnect();
  795. // }, 190000);
  796. // break;
  797. }
  798. });
  799.  
  800. function paint_two_coords() {
  801.  
  802. }
  803. let calc_x, calc_y, magshot_x, magshot_y;
  804.  
  805. function manageDamageCalc() {
  806. // если бой не начался, популизирует mapobj
  807. if (lastturn < 0) {
  808. for (const cre of Object.values(stage.pole.obj)) {
  809. unsafeWindow.mapobj[cre.x + cre.y * defxn] = cre.obj_index;
  810. }
  811. }
  812. let cre_collection = unsafeWindow.stage.pole.obj
  813. if (mapobj[xr_last + yr_last * defxn] === undefined || cre_collection[mapobj[xr_last + yr_last * defxn]].rock === 1) {
  814. paint_coords(xr_last, yr_last, "#cccccc")
  815. return
  816. }
  817. if (calc_x === undefined) {
  818. [calc_x, calc_y] = [xr_last, yr_last];
  819. paint_coords(xr_last, yr_last, "#800000");
  820. let attacker = cre_collection[mapobj[calc_x + calc_y * defxn]]
  821. if (attacker.hero === 1) {
  822. readjust_elements();
  823. individual_calc.innerHTML = ` <div id="individual_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  824. <span>Урон <br>
  825. </span>
  826. <b>${attacker.nametxt}</b> по
  827. <br>
  828. </div>
  829. `;
  830. }
  831. } else {
  832. readjust_elements();
  833. let atk_obj_index = unsafeWindow.mapobj[calc_x + calc_y * defxn]
  834. let def_obj_index = unsafeWindow.mapobj[xr_last + yr_last * defxn]
  835. set_Display([individual_calc, collapse_button], "inline")
  836. if (cre_distance_on) {
  837. cre_distance_div.style.display = "inline";
  838. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  839. }
  840. individual_calc.innerHTML = individual_calc_innerHTML(atk_obj_index, def_obj_index);
  841. calc_x = calc_y = undefined
  842. paint_coords(xr_last, yr_last, "blue")
  843. }
  844. }
  845.  
  846. // если есть настройка подтверждения хода = моб. версия, + поддержка моб версии
  847. const mobileInterval = setInterval(() => {
  848. if ([typeof android, typeof iOS].includes("undefined")) return;
  849. clearInterval(mobileInterval);
  850. if (!android && !iOS) return;
  851. const helpButtonHTML = `<div id="help_buttonScript" class="toolbars_mobile_img"><span style = "color:white;">урон</span><img id = "help_imgScript" src="https://dcdn.heroeswm.ru/i/combat/btn_help.png?v=6" style="opacity:0.5"><br></div>`
  852. document.querySelector("#left_button").insertAdjacentHTML("beforeEnd", helpButtonHTML);
  853. const helpButton = document.querySelector("#help_buttonScript");
  854. helpButton.addEventListener("touchend", event => {
  855. calc_x = calc_y = undefined;
  856. const firstTime = localStorage.getItem("battle_damage_tooltip_mobile_first_time");
  857. if (!firstTime) {
  858. localStorage.setItem("battle_damage_tooltip_mobile_first_time", 1);
  859. alert("Кнопка с вопросительным знаком -- активация просмотра урона в скрипте battle_damage_tooltip. Чтобы посмотреть урон, нужно, чтобы эта кнопка была активной. Тап на атакующее существо (клетка с существом помечается красным цветом), затем тап на атакуемое существо (клетка синим цветом). Урон будет в боевом чате");
  860. }
  861. const img = helpButton.querySelector("img");
  862. img.style.opacity = img.style.opacity === "0.5" ? "1" : "0.5";
  863. helpButton.classList.toggle("active");
  864. })
  865. document.addEventListener("touchend", event => {
  866. info_btn_cnt = 0;
  867. if (!helpButton.classList.contains("active") || event.target.id === "help_imgScript") return;
  868. manageDamageCalc();
  869. })
  870.  
  871. }, 100);
  872.  
  873. // Урон одного стека по другому по выбору нажатием кнопки E
  874.  
  875. window.addEventListener("keyup", event => {
  876. const keyCode = parseInt(event.keyCode);
  877. if ((document.querySelector("#chattext") === document.activeElement) || (document.querySelector("#chattext_classic") === document.activeElement)) return;
  878. if (keyCode === keyboardKeycodes[seeDamage.toLowerCase()]) manageDamageCalc();
  879. if (event.target.id === "uprava_filter_input"){
  880. upravaEvent(event);
  881. }
  882. if (keyCode === keyboardKeycodes[seeMagShot.toLowerCase()]) {
  883. if (!magshot_x) {
  884. [magshot_x, magshot_y] = [xr_last, yr_last]
  885. paint_coords(xr_last, yr_last, "#FC7052", 4000)
  886. } else {
  887. paint_coords(xr_last, yr_last, "#7A71FE", 4000)
  888. magshot(magshot_x, magshot_y, xr_last, yr_last)
  889. magshot_x = magshot_y = null
  890. }
  891. }
  892.  
  893. });
  894. // -----------------------------------
  895.  
  896. // ========= battleHelper ============
  897. // function wrap_battlehelper() {
  898. // for (const child of battlehelper_div.children) {
  899. // if (child.className === "cont") return
  900. // }
  901. // readjust_elements();
  902. // let el_transfer = [];
  903. // [...outer_chat.children].forEach(child => {
  904. // if (["B", "BR"].includes(child.tagName) || child.className == "cont") {
  905. // el_transfer.push(child)
  906. // }
  907. // });
  908. // for (const el of el_transfer) battlehelper_div.appendChild(el);
  909. // const first_icons = battlehelper_div.querySelectorAll('br + div.cont');
  910. // let teams_text = [...outer_chat.childNodes].filter(node => (node.nodeType === node.TEXT_NODE && /Команда №(\d)/.test(node.textContent.trim())));
  911. // let i = 0
  912. // for (const img_div of first_icons) {
  913. // img_div.previousSibling.insertAdjacentHTML('beforebegin', teams_text[i].textContent);
  914. // i++;
  915. // }
  916. // for (const el of teams_text) el.remove()
  917. // let title_arr = [...battlehelper_div.children].filter(child => child.textContent === "Стартовый бонус АТБ")
  918. // if (battlehelper_div.children.length === 2 && title_arr.length === 1) {
  919. // battlehelper_div.innerHTML = " "
  920. // }
  921. // }
  922. // observer.observe(outer_chat, { childList: true });
  923. // setTimeout(function() {
  924. // observer.disconnect();
  925. // }, 30000);
  926.  
  927. // -----------------------------------
  928. // ========= маг. урон ============
  929.  
  930. const damageSpells = {
  931. "meteor": "Метеоритный дождь",
  932. "lighting": "Молния",
  933. "implosion": "Взрыв",
  934. "fireball": "Огненный шар",
  935. "chainlighting": "Цепная молния",
  936. "firewall": "Огненная стена",
  937. "magicarrow": "Магическая стрела",
  938. "stonespikes": "Каменные шипы",
  939. "magicfist": "Магический кулак",
  940. "icebolt": "Ледяная глыба",
  941. "circle_of_winter": "Кольцо холода",
  942. "swarm": "Осиный рой",
  943. "angerofhorde": "Ярость орды",
  944. "poison": "Разложение",
  945. "stormcaller": "Зов бури",
  946. "calllightning": "Зов молний",
  947. "firearrow": "Огненная стрела",
  948. "divinev": "Божественная месть"
  949.  
  950. }
  951.  
  952. function calcFactionModifier(attacker, defender) {
  953. let modifier, k;
  954. if ((umelka[attacker['owner']][0] > 0) && (umelka[defender['owner']][0] > 0)) {
  955. k = umelka[attacker['owner']][0];
  956. if ((k > 0) && (k < 11)) {
  957. let j = umelka[defender['owner']][k];
  958. modifier = 1 - j * 0.03;
  959. };
  960. };
  961. return modifier;
  962. }
  963.  
  964. function calcHellFire(attacker, defender, cre_collection) {
  965. const factionModifier = calcFactionModifier(attacker, defender);
  966. const spellPower = cre_collection[heroes[attacker.owner]].maxnumber;
  967. const perkModifier = isperk(attacker.obj_index, 104) ? 1.5 : 1;
  968. // console.log("round: ", Math.round((7 * spellPower + 7) * perkModifier) * factionModifier);
  969. const res = Math.floor(Math.round((7 * spellPower + 7) * perkModifier) * factionModifier);
  970. // console.log("floor: ", Math.floor((7 * spellPower + 7) * perkModifier) * factionModifier);
  971. // return Math.round((7 * spellPower + 7) * perkModifier * factionModifier);
  972. return res;
  973. }
  974. // добавление spellname_magiceff для объекта для дальнийших расчетов
  975. function initEff(s, activeobj_S) { // s = spell name
  976. if (stage[war_scr].obj[activeobj_S][s + 'effmain'] > 0) {
  977. let eff;
  978. if (stage[war_scr].obj[activeobj_S].hero) {
  979. var s1 = 0;
  980. if ((isperk(activeobj_S, 93)) && ((s == 'magicfist') || (s == 'raisedead'))) { s1 = 4; };
  981. if ((isperk(activeobj_S, 78)) && ((s == 'poison') || (s == 'mpoison'))) { s1 += 5; };
  982. if ((isperk(activeobj_S, 89)) && ((s == 'poison') || (s == 'mpoison'))) { s1 += 3; };
  983. 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));
  984. if (stage[war_scr].obj[activeobj_S][s + 'effmult'] == 1.5) { eff = Math.round(eff); };
  985. var teff = eff;
  986. } else {
  987. 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));
  988. if (s == 'blind') {
  989. 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']);
  990. };
  991. var teff = eff;
  992. }
  993. stage[war_scr].obj[activeobj_S][s + '_magiceff'] = eff;
  994. }
  995. }
  996.  
  997. function initMagicCalc() {
  998.  
  999.  
  1000. // родной calcmagic с удалением кодом массовых заклов и др. побочных эффектов наведения курсора с активным заклом
  1001. unsafeWindow.stage.pole.calcmagic_script = function calcmagic(atk_x, atk_y, xr, yr, magicuse, penalty = 1) {
  1002. //console.log(magicuse);
  1003. let i = mapobj[atk_x + defxn * atk_y];
  1004. const activeobj_S = i;
  1005. initEff(magicuse, i);
  1006. unsafeWindow.Totalmagicdamage = 0;
  1007. unsafeWindow.Totalmagickills = 0;
  1008.  
  1009. var ok = false;
  1010. unsafeWindow.mul = 1;
  1011. var len = unsafeWindow.stage.pole.obj_array.length;
  1012. for (var k1 = 0; k1 < len; k1++) {
  1013. var j = unsafeWindow.stage.pole.obj_array[k1];
  1014. unsafeWindow.stage.pole.obj[j]['attacked'] = 1;
  1015. unsafeWindow.stage.pole.obj[j]['attacked2'] = 1;
  1016. };
  1017.  
  1018. if ((magicuse == 'magicfist') || (magicuse == 'angerofhorde')) {
  1019. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  1020. if ((magicuse == 'magicfist') && (unsafeWindow.stage.pole.obj[mapobj[xr + yr * defxn]]['organicarmor'])) eff = Math.round(eff * 0.2);
  1021. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], eff, 'neutral', magicuse, 0, 0, 0);
  1022. ok = true;
  1023. };
  1024. if (magicuse == 'swarm') {
  1025. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'], 'other', magicuse, 0, 0, 0);
  1026. ok = true;
  1027. };
  1028. if (magicuse === "divinev") {
  1029. var separhsum = (stage.pole.obj[mapobj[xr + yr * defxn]].separhsum ? 1 : 0);
  1030. var eff = (stage.pole.obj[i]['divineveffmain'] + Math.round(stage.pole.obj[i]['divineveffmult'] * Math.pow(stage.pole.obj[i]['nownumber'], 0.7))) * Math.sqrt(separhsum);
  1031. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], eff, 'other', 'divinev', 0, 0, 0);
  1032. ok = true;
  1033. }
  1034. if ((magicuse == 'magicarrow') || (magicuse == 'lighting')) {
  1035. if (unsafeWindow.stage.pole.obj[activeobj_S]['calllightning']) {
  1036. unsafeWindow.stage.pole.obj[activeobj_S]['lighting_magiceff'] = 50 * unsafeWindow.stage.pole.obj[activeobj_S]['nownumber'];
  1037. };
  1038. 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);
  1039. ok = true;
  1040. };
  1041. if (magicuse == 'firearrow') {
  1042. 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);
  1043. ok = true;
  1044. };
  1045. if (magicuse == 'icebolt') {
  1046. 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);
  1047. ok = true;
  1048. };
  1049. if (magicuse == 'implosion') {
  1050. 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);
  1051. ok = true;
  1052. };
  1053.  
  1054. if (magicuse == 'poison') {
  1055. unsafeWindow.stage.pole.calcpoison(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff']);
  1056. ok = true;
  1057. };
  1058. if (magicuse == 'meteor') {
  1059. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  1060. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(eff * mul), 'earth', magicuse, 0, 0, 0);
  1061. ok = true;
  1062. };
  1063. if (magicuse == 'chainlighting') {
  1064. var eff = unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'];
  1065. if (unsafeWindow.stage.pole.obj[activeobj_S]['spmult'] > 1) {
  1066. 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)));
  1067. }
  1068. if (penalty === 1) {
  1069. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(eff * mul), 'air', 'lighting', 0, 0, 0);
  1070. } else {
  1071. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.floor(Math.round(eff * mul) * penalty), 'air', 'lighting', 0, 0, 0);
  1072. }
  1073. ok = true;
  1074. };
  1075.  
  1076. if (magicuse == 'fireball') {
  1077. 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);
  1078. ok = true;
  1079. };
  1080. if (magicuse == 'stormcaller') {
  1081. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], Math.round(unsafeWindow.stage.pole.obj[activeobj_S].nownumber * 10), 'air', magicuse, 0, 0, 0);
  1082. ok = true;
  1083. };
  1084. if (magicuse == 'firewall') {
  1085. unsafeWindow.stage.pole.attackmagic(i, mapobj[xr + yr * defxn], unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff'], 'fire', magicuse, 0, 0, 0);
  1086. ok = true;
  1087. };
  1088. if (magicuse == 'circle_of_winter') {
  1089. //console.log("mul", mul);
  1090. //console.log("eff", unsafeWindow.stage.pole.obj[activeobj_S][magicuse + '_magiceff']);
  1091. 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);
  1092. ok = true;
  1093. };
  1094.  
  1095. if (magicuse == 'stonespikes') {
  1096. // 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);
  1097. // 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);
  1098. // 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);
  1099. // 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);
  1100. 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);
  1101. ok = true;
  1102. };
  1103. // 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']))) {
  1104. // unsafeWindow.stage.pole.showatb();
  1105. // };
  1106.  
  1107. // 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']))) {
  1108. // unsafeWindow.stage.pole.showatb();
  1109. // };
  1110. return Totalmagicdamage;
  1111. };
  1112. // копипаст с удаленем запрета на показ урона по своим стекам
  1113. stage.pole.attackmagic = function attackmagic(attacker, defender, eff, element, iname, noexp, nodamage, nomult) {
  1114. if (defender == 1000) return 0;
  1115. if ((defender <= 0) || (defender == undefined) || (!this.obj[defender])) return 0;
  1116. // if (this.obj[attacker].getside()==this.obj[defender]['side']) return 0;
  1117. if ((this.obj[defender]['rock']) || (this.obj[defender]['hero'])) return 0;
  1118. if (!nomult) nomult = 0;
  1119. if (this.obj[defender]['y'] < 0) return 0;
  1120. if (this.obj[defender]['attacked'] != 1) return 0;
  1121.  
  1122. if ((magic[attacker]['apc']) && (magic[attacker]['apc']['effect'] > 0)) {
  1123. eff *= magic[attacker]['apc']['effect'] / 100;
  1124. };
  1125. if (this.obj[defender]['building']) {
  1126. eff *= 0.05;
  1127. };
  1128. if ((magic[defender]['enc']) && (magic[defender]['enc']['effect'] == 1)) {
  1129. eff *= 0.5;
  1130. };
  1131.  
  1132. if (this.obj[attacker]['forbiddenspell']) {
  1133. eff *= this.check_forbiddenspell(attacker);
  1134.  
  1135. }
  1136.  
  1137. this.obj[defender]['attacked'] = 0;
  1138. if ((this.obj[defender]['owner'] == 2) && ((is_naim_guild(btype)) || ((btype != 13) && (plid2 == -2))) && (this.obj[attacker]['hero'])) {
  1139. eff *= checkmage(this.obj[attacker]['owner'], iname);
  1140. };
  1141.  
  1142. if ((btype == 108) && (checkwall2(this.obj[attacker]['x'], this.obj[attacker]['y'], this.obj[defender]['x'], this.obj[defender]['y'], attacker))) eff *= 0.5;
  1143. if ((btype == 118) && (checkwall2(this.obj[attacker]['x'], this.obj[attacker]['y'], this.obj[defender]['x'], this.obj[defender]['y'], attacker))) eff *= 0.5;
  1144.  
  1145.  
  1146. var hera = 0;
  1147. var herd = 0;
  1148. var len = this.obj_array.length;
  1149. for (var k1 = 0; k1 < len; k1++) {
  1150. var k = this.obj_array[k1];
  1151. if ((this.obj[k].hero) && (this.obj[k].owner == this.obj[attacker].owner)) hera = k;
  1152. if ((this.obj[k].hero) && (this.obj[k].owner == this.obj[defender].owner)) herd = k;
  1153. };
  1154.  
  1155. if ((hera > 0) && (magic[hera]['bna'])) {
  1156. eff = eff * (1 + magic[hera]['bna']['effect'] / 100);
  1157. };
  1158. if ((!this.obj[attacker]['hero']) && (isperk(attacker, _PERK_BLESS))) {
  1159. eff *= 1.04;
  1160. };
  1161. if ((herd > 0) && (magic[herd]['bnd'])) {
  1162. eff = eff / (1 + magic[herd]['bnd']['effect'] / 100);
  1163. };
  1164. if ((herd > 0) && (magic[herd]['fld'])) {
  1165. eff = eff * (1 - magic[herd]['fld']['effect'] / 100);
  1166. };
  1167. if ((herd > 0) && (magic[herd]['rcd']) && (monster_race[this.obj[attacker]['id']] == magic[herd]['rcd']['effect'])) {
  1168. eff = eff * 0.93;
  1169. };
  1170.  
  1171. if ((!this.obj[attacker]['hero']) && (magic[attacker]['zat']) && ((magic[attacker]['zat']['effect'] == 1) || (magic[attacker]['zat']['effect'] == 2))) {
  1172. eff *= 1.15;
  1173. };
  1174.  
  1175.  
  1176. if ((magic[defender]['sum']) && (isperk(attacker, _PERK_EXORCISM)) && (nomult == 0)) {
  1177. eff *= 2;
  1178. };
  1179.  
  1180.  
  1181. //eff1=24 eff2=24 eff3=31.056 eff4=27.28 imm=70.6 imm2=83.0068 eff5=22.64425504
  1182. eff = this.calceffmagic(attacker, defender, eff, element);
  1183. ignor = 0;
  1184. if ((magic[defender]['mmn']) && (element != 'neutral')) {
  1185. eff *= 1 + magic[defender]['mmn']['effect'] / 100;
  1186. }
  1187.  
  1188. if ((hera > 0) && (this.obj[hera]['hero'])) {
  1189. h = hera;
  1190. if (nomult == 0) {
  1191. if ((magic[h]['_en']) && (element == 'neutral')) {
  1192. eff *= 1 + magic[h]['_en']['effect'] / 100;
  1193. };
  1194. if ((magic[h]['_ea']) && (element == 'air')) {
  1195. eff *= 1 + magic[h]['_ea']['effect'] / 100;
  1196. };
  1197. if ((magic[h]['_ew']) && (element == 'cold')) {
  1198. eff *= 1 + magic[h]['_ew']['effect'] / 100;
  1199. };
  1200. if ((magic[h]['_ef']) && (element == 'fire')) {
  1201. eff *= 1 + magic[h]['_ef']['effect'] / 100;
  1202. };
  1203. if ((magic[h]['_ee']) && (element == 'earth')) {
  1204. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  1205. };
  1206. };
  1207.  
  1208. if ((magic[h]['_Ia']) && ((element == 'air') || (iname == 'lighting'))) {
  1209. ignor = magic[h]['_Ia']['effect'] / 100;
  1210. };
  1211. if ((magic[h]['_Iw']) && (element == 'cold')) {
  1212. ignor = magic[h]['_Iw']['effect'] / 100;
  1213. };
  1214. if ((magic[h]['_If']) && (element == 'fire')) {
  1215. ignor = magic[h]['_If']['effect'] / 100;
  1216. };
  1217. if ((magic[h]['_Ie']) && (element == 'earth')) {
  1218. ignor = magic[h]['_Ie']['effect'] / 100;
  1219. };
  1220. };
  1221.  
  1222. magicdamage = Math.round(eff);
  1223. if ((umelka[this.obj[attacker]['owner']][0] > 0) && (umelka[this.obj[defender]['owner']][0] > 0)) {
  1224. var k = umelka[this.obj[attacker]['owner']][0];
  1225. if ((k > 0) && (k < 11)) {
  1226. j = umelka[this.obj[defender]['owner']][k];
  1227. magicdamage = magicdamage * (100 - j * 3) / 100;
  1228. };
  1229. };
  1230.  
  1231. immune = this.getattackimmune(attacker, defender, element, iname, 1);
  1232. if (hera > 0) {
  1233. h = hera;
  1234. if ((magic[h]['nut']) && (plid2 == -2)) {
  1235. magicdamage = magicdamage * (100 + magic[h]['nut']['effect']) / 100;
  1236. };
  1237. if ((magic[h]['imd'])) {
  1238. ignor = 1 - (1 - ignor) * (1 - magic[h]['imd']['effect'] / 100);
  1239. };
  1240. if ((this.obj[defender]['mechanical']) && (magic[hera]['MEC']) && (element == 'neutral')) {
  1241. magicdamage *= 1 + magic[hera]['MEC']['effect'] / 100;
  1242. };
  1243. };
  1244.  
  1245.  
  1246.  
  1247. if (isperk(defender, _PERK_BONEWARD)) {
  1248. immune *= 0.8;
  1249. };
  1250. immune2 = 0;
  1251. if (element != 'neutral') {
  1252. var xx = 0,
  1253. yy = 0,
  1254. xx1 = 0,
  1255. yy1 = 0;
  1256.  
  1257. var bigx = this.obj[defender]['big'];
  1258. var bigy = this.obj[defender]['big'];
  1259. if (this.obj[defender]['bigx']) bigx = 1;
  1260. if (this.obj[defender]['bigy']) bigy = 1;
  1261.  
  1262. for (xx = -1; xx <= 1 + bigx; xx++) {
  1263. for (yy = -1; yy <= 1 + bigy; yy++) {
  1264. xx1 = this.obj[defender]['x'] + xx;
  1265. yy1 = this.obj[defender]['y'] + yy;
  1266. 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'])) {
  1267. if (immune2 < this.obj[mapobj[xx1 + yy1 * defxn]]['nownumber']) {
  1268. immune2 = this.obj[mapobj[xx1 + yy1 * defxn]]['nownumber'];
  1269. var mg = mapobj[xx1 + yy1 * defxn];
  1270. };
  1271. break;
  1272. };
  1273. };
  1274. };
  1275. immune2 = Math.min(100, immune2);
  1276. if ((this.obj[defender]['enchantedarmor']) && (this.obj[defender]['nownumber'] > 0) && (this.obj[attacker]['side'] == this.obj[defender]['side'])) { immune2 = 100; var mg = defender; };
  1277. };
  1278. if (this.obj[defender]['organicarmor']) ignor = 0;
  1279. immune1 = (100 - (100 - immune) * (1 - ignor));
  1280. dambefore = Math.round(magicdamage * immune1 / 100);
  1281. immune *= 1 - immune2 / 100;
  1282. immune = (100 - (100 - immune) * (1 - ignor));
  1283.  
  1284.  
  1285.  
  1286. magicdamage = Math.round(magicdamage * immune / 100);
  1287.  
  1288.  
  1289. if (magic[defender]['rag']) {
  1290. magicdamage = this.ragedamage(defender, magicdamage);
  1291. };
  1292.  
  1293.  
  1294. Totalmagicdamage += magicdamage;
  1295. var totalh = (this.obj[defender]['nownumber'] - 1) * this.obj[defender]['maxhealth'] + this.obj[defender]['nowhealth'];
  1296. var kills = Math.floor(Math.min(magicdamage, totalh) / this.obj[defender]['maxhealth']);
  1297. var nowhealth = this.obj[defender]['nowhealth'] - (Math.min(magicdamage, totalh) - kills * this.obj[defender]['maxhealth']);
  1298. if (nowhealth <= 0) kills++;
  1299. Totalmagickills += kills;
  1300.  
  1301. 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']))) {
  1302. var a = 0.3;
  1303. if (this.obj[activeobj]['master_of_storms']) a = this.obj[activeobj]['master_of_storms'] / 100;
  1304. init = Math.floor((100 - this.obj[defender]['nowinit'] + this.obj[attacker]['nowinit']) * a);
  1305. this.obj[defender]['reset_init'] = init;
  1306. };
  1307. 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']))) {
  1308. var a = 30;
  1309. if (this.obj[activeobj]['master_of_ice']) a = this.obj[activeobj]['master_of_ice'];
  1310. setn_temp_magic(defender, 'cld', a);
  1311. };
  1312.  
  1313.  
  1314. }
  1315. stage.pole.calcpoison = function calcpoison(i, j, eff) {
  1316. var defender = j;
  1317. var attacker = i;
  1318.  
  1319. function experimental() {
  1320. if ((magic[attacker]['apc']) && (magic[attacker]['apc']['effect'] > 0)) {
  1321. eff *= magic[attacker]['apc']['effect'] / 100;
  1322. };
  1323. if (stage.pole.obj[attacker]['forbiddenspell']) {
  1324. eff *= stage.pole.check_forbiddenspell(attacker);
  1325. }
  1326. if ((!stage.pole.obj[attacker]['hero']) && (isperk(attacker, _PERK_BLESS))) {
  1327. eff *= 1.04;
  1328. };
  1329. if ((herd > 0) && (magic[herd]['fld'])) {
  1330. eff = eff * (1 - magic[herd]['fld']['effect'] / 100);
  1331. };
  1332. if ((herd > 0) && (magic[herd]['rcd']) && (monster_race[stage.pole.obj[attacker]['id']] == magic[herd]['rcd']['effect'])) {
  1333. eff = eff * 0.93;
  1334. };
  1335. if ((!stage.pole.obj[attacker]['hero']) && (magic[attacker]['zat']) && ((magic[attacker]['zat']['effect'] == 1) || (magic[attacker]['zat']['effect'] == 2))) {
  1336. eff *= 1.15;
  1337. };
  1338. if ((magic[defender]['sum']) && (isperk(attacker, _PERK_EXORCISM)) && (nomult == 0)) {
  1339. eff *= 2;
  1340. };
  1341.  
  1342. if ((hera > 0) && (stage.pole.obj[hera]['hero'])) {
  1343. h = hera;
  1344. if (nomult == 0) {
  1345. if ((magic[h]['_ee'])) {
  1346. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  1347. };
  1348. };
  1349. if ((magic[h]['_Ie'])) {
  1350. ignor = magic[h]['_Ie']['effect'] / 100;
  1351. };
  1352. };
  1353.  
  1354.  
  1355. }
  1356. //experimental();
  1357.  
  1358. if ((defender <= 0) || (defender == undefined)) return 0;
  1359. // if (stage.pole.obj[attacker].getside() == stage.pole.obj[defender]['side']) return 0;
  1360. if ((stage.pole.obj[defender]['rock']) || (stage.pole.obj[defender]['hero'])) return 0;
  1361. if (stage.pole.obj[defender]['y'] < 0) return 0;
  1362. if (stage.pole.obj[defender]['attacked'] != 1) return 0;
  1363. stage.pole.obj[defender]['attacked'] = 0;
  1364. var hera = 0;
  1365. var herd = 0;
  1366. var attacker = i;
  1367. var len = stage.pole.obj_array.length;
  1368. for (var k1 = 0; k1 < len; k1++) {
  1369. var k = stage.pole.obj_array[k1];
  1370. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[attacker].owner)) hera = k;
  1371. if ((stage.pole.obj[k].hero) && (stage.pole.obj[k].owner == stage.pole.obj[defender].owner)) herd = k;
  1372. };
  1373. if (stage.pole.obj[j]['absolutepurity']) eff = 0;
  1374. if (stage.pole.obj[j]['building']) eff *= 0.05;
  1375. if (hera > 0) {
  1376. h = hera;
  1377. if (magic[h]['_ee']) {
  1378. eff *= 1 + magic[h]['_ee']['effect'] / 100;
  1379. };
  1380. eff = Math.round(eff);
  1381. if ((hera > 0) && (magic[hera]['bna'])) {
  1382. eff = Math.round(eff * (1 + magic[hera]['bna']['effect'] / 100));
  1383. };
  1384. if ((herd > 0) && (magic[herd]['bnd'])) {
  1385. eff = Math.round(eff / (1 + magic[herd]['bnd']['effect'] / 100));
  1386. };
  1387. if (stage.pole.obj[j]['vulnerabletoshadowmagic']) eff *= 1.25;
  1388. };
  1389. eff = Math.round(eff);
  1390. var magicdamage = eff;
  1391. if ((umelka[stage.pole.obj[attacker]['owner']][0] > 0) && (umelka[stage.pole.obj[defender]['owner']][0] > 0)) {
  1392. var k = umelka[stage.pole.obj[attacker]['owner']][0];
  1393. if ((k > 0) && (k < 11)) {
  1394. j = umelka[stage.pole.obj[defender]['owner']][k];
  1395. magicdamage = magicdamage * (100 - j * 3) / 100;
  1396. };
  1397. };
  1398. magicdamage = Math.round(magicdamage);
  1399.  
  1400. Totalmagicdamage += magicdamage;
  1401. Totalmagicdamage = Math.round(Totalmagicdamage / 1.1);
  1402. var totalh = (stage.pole.obj[defender]['nownumber'] - 1) * stage.pole.obj[defender]['maxhealth'] + stage.pole.obj[defender]['nowhealth'];
  1403. var kills = Math.floor(Math.min(magicdamage, totalh) / stage.pole.obj[defender]['maxhealth']);
  1404. var nowhealth = stage.pole.obj[defender]['nowhealth'] - (Math.min(magicdamage, totalh) - kills * stage.pole.obj[defender]['maxhealth']);
  1405. if (nowhealth <= 0) kills++;
  1406. Totalmagickills += kills;
  1407. };
  1408. unsafeWindow.check_keys = function check_keys(key) {
  1409. if (key == 27) {
  1410. if ((buttons_visible['magicbook_button_close']) || (buttons_visible['magicbook_button_close2']))
  1411. hide_magic_book();
  1412. if (buttons_visible['rune_off_button'])
  1413. rune_button_off_onRelease();
  1414. if (buttons_visible['info_off'])
  1415. info_off_onRelease();
  1416. if ((buttons_visible['oneskill_button_close']) || (buttons_visible['oneskill_button_close2'])) {
  1417. stage[war_scr].oneskillbutton_onRelease();
  1418. };
  1419. hide_button('win_InfoCreature');
  1420. hide_button('win_InfoHero');
  1421. hide_button('win_InfoHero2');
  1422. hide_button('win_InfoCreatureEffect');
  1423. };
  1424. if (chatfocus) {
  1425. if (key == 13) {
  1426. btn_SendChatMessage_release();
  1427. };
  1428. return 0;
  1429. }
  1430. if ((key == 68) && ((buttons_visible['defend_button']) || (buttons_visible['defend_button2'])))
  1431. defend_button_release();
  1432. if (key == 32) {
  1433. if (buttons_visible['pause_button']) {
  1434. pause_button_onRelease();
  1435. } else if (buttons_visible['play_button']) {
  1436. play_button_onRelease();
  1437. };
  1438. };
  1439. if ((key == 87) && ((buttons_visible['wait_button']) || (buttons_visible['wait_button2'])))
  1440. wait_button_release();
  1441. if (key == 67) {
  1442. if ((buttons_visible['magicbook_button']) || (buttons_visible['magicbook_button2']))
  1443. magicbook_button_release();
  1444. else if ((buttons_visible['magicbook_button_close']) || (buttons_visible['magicbook_button_close2']))
  1445. hide_magic_book();
  1446. if ((buttons_visible['oneskill_button']) || (buttons_visible['oneskill_button2']) || (buttons_visible['oneskill_button_close']) || (buttons_visible['oneskill_button_close2'])) {
  1447. stage[war_scr].oneskillbutton_onRelease();
  1448. };
  1449. };
  1450. }
  1451. let defend_button_release = function defend_button_release() {
  1452. if ((is_visible_element('magic_book')) || (buttons_visible['scroll_runes'])) {
  1453. return 0;
  1454. }
  1455. if ((someactive) || (!inserted)) {
  1456. return 0;
  1457. }
  1458. if (Object.values(heroes).includes(activeobj) && activeobj !== 0) {
  1459. alert("Скрипт battle_damage_tooltip заблокировал оборону во время хода героя! Клик по кнопке свободен.")
  1460. return 0;
  1461. }
  1462. if ((loader.loading) || (activeobj == 0)) {
  1463. return 0;
  1464. }
  1465. if ((info_button) && (android)) {
  1466. return 0;
  1467. };
  1468. loader.loading = true;
  1469. pl_id = player;
  1470. if (player2 > 0)
  1471. pl_id = player2;
  1472. loadmy('battle.php?warid=' + warid + '&move=1&defend=1&pl_id=' + pl_id + '&my_monster=' + activeobj + '&x=' + stage[war_scr].obj[activeobj].x + '&y=' + stage[war_scr].obj[activeobj].y + '&lastturn=' + lastturn + '&lastmess=' + lastmess + '&lastmess2=' + lastmess2 + '&rand=' + mathrandom());
  1473. }
  1474. }
  1475. // -----------------------------------
  1476.  
  1477. // Функция рельсы гвд с поправкой на выбор клеток юзером
  1478. function magshot(x1, y1, xr, yr) {
  1479. var x2 = xr;
  1480. var y2 = yr;
  1481. var dx = Math.abs(x1 - x2);
  1482. var dy = Math.abs(y1 - y2);
  1483. var skip = false;
  1484. if (x1 < x2) {
  1485. var xp = 1;
  1486. } else {
  1487. var xp = -1;
  1488. };
  1489. if (y1 < y2) {
  1490. var yp = 1;
  1491. } else {
  1492. var yp = -1;
  1493. };
  1494. if (dx > dy) {
  1495. if (x1 > x2) {
  1496. var x = -5;
  1497. } else {
  1498. var x = defxn + 3 - 1;
  1499. };
  1500. var y = (y2 - y1) / (x2 - x1) * (x - x1) + y1;
  1501. } else {
  1502. if (y1 > y2) {
  1503. var y = -5;
  1504. } else {
  1505. var y = defyn + 5 + 1;
  1506. };
  1507. var x = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
  1508. };
  1509. x = x1;
  1510. y = y1;
  1511. while ((x > 0) && (y > 0) && (x <= defxn - 2) && (y <= defyn)) {
  1512. if (dx > dy) {
  1513. x += xp;
  1514. y = (y2 - y1) / (x2 - x1) * (x - x1) + y1;
  1515. } else {
  1516. y += yp;
  1517. x = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
  1518. };
  1519. let shot_coords = []
  1520. if ((Math.round(x) > 0) && (Math.round(y) > 0) && (Math.round(x) <= defxn - 2) && (Math.round(y) <= defyn)) {
  1521. if (shado[Math.round(x) + Math.round(y) * defxn]) {
  1522. set_visible(shado[Math.round(x) + Math.round(y) * defxn], 1);
  1523. shot_coords.push({ x: Math.round(x), y: Math.round(y) })
  1524. }
  1525. };
  1526. setTimeout(() => {
  1527. for (const coord of shot_coords) {
  1528. set_visible(shado[coord.x + coord.y * defxn], 0);
  1529. }
  1530. }, 4000)
  1531. };
  1532. };
  1533.  
  1534. // Родная функция гвд с поправками на переменную l и модификаторами magic[]
  1535. function attackmonster(attacker, ax, ay, x, y, defender, cre_distance, shootok, koef, inuse) {
  1536. let cre_collection = unsafeWindow.stage.pole.obj
  1537. var mainattack = 1;
  1538. var ax1 = ax;
  1539. var ay1 = ay;
  1540. if (defender == 1000) return 0;
  1541. if (defender <= 0) return 0;
  1542. if (!cre_collection[defender]) return 0;
  1543. if (cre_collection[defender]['hero']) return 0;
  1544. if (cre_collection[defender]['rock']) return 0;
  1545. if (koef == undefined) koef = 1;
  1546. if (inuse == undefined) inuse = '';
  1547. var len = unsafeWindow.wmap2[y * defxn + x];
  1548. if ((cre_collection[attacker].x == x) && (cre_collection[attacker].y == y)) len = spd;
  1549. shootok = 1;
  1550.  
  1551. function getAdjacentAndDiagonalCoords(x, y) {
  1552. const adjacentAndDiagonalCoords = [];
  1553. adjacentAndDiagonalCoords.push([x + 1, y]);
  1554. adjacentAndDiagonalCoords.push([x - 1, y]);
  1555. adjacentAndDiagonalCoords.push([x, y + 1]);
  1556. adjacentAndDiagonalCoords.push([x, y - 1]);
  1557. adjacentAndDiagonalCoords.push([x + 1, y + 1]);
  1558. adjacentAndDiagonalCoords.push([x - 1, y + 1]);
  1559. adjacentAndDiagonalCoords.push([x + 1, y - 1]);
  1560. adjacentAndDiagonalCoords.push([x - 1, y - 1]);
  1561. return adjacentAndDiagonalCoords;
  1562. }
  1563.  
  1564. if (cre_collection[attacker].shots === 0) {
  1565. shootok = 0
  1566. } else {
  1567. let attacker_adjacent_coords = getAdjacentAndDiagonalCoords(stage.pole.obj[attacker].x, stage.pole.obj[attacker].y)
  1568. let enemies_list = Object.values(stage.pole.obj).filter(creature => creature.side != stage.pole.obj[attacker].side)
  1569. enemies_list.forEach(enemy => {
  1570. attacker_adjacent_coords.forEach(coord => {
  1571. if (coord[0] == enemy.x && coord[1] == enemy.y && ![0, -1].includes(enemy.nownumber)) shootok = 0
  1572. })
  1573. })
  1574. }
  1575. if (cre_collection[attacker]['big']) {
  1576. if (ax > x) {
  1577. x++;
  1578. };
  1579. if (ay > y) {
  1580. y++;
  1581. };
  1582. };
  1583. if (cre_collection[attacker]['bigx']) {
  1584. if (ax > x) {
  1585. x++;
  1586. };
  1587. };
  1588. if (cre_collection[attacker]['bigy']) {
  1589. if (ay > y) {
  1590. y++;
  1591. };
  1592. };
  1593. var spd = Math.max(0, Math.round((cre_collection[attacker].speed + cre_collection[attacker]['ragespeed'] + cre_collection[attacker]['speedaddon']) * cre_collection[attacker].speedmodifier));
  1594. if (unsafeWindow.magic[attacker]['ent']) {
  1595. spd = 0;
  1596. };
  1597. var movelen = spd - len;
  1598. unsafeWindow.attacker_c = attacker;
  1599. unsafeWindow.ax_c = ax;
  1600. unsafeWindow.ay_c = ay;
  1601. unsafeWindow.x_c = x;
  1602. unsafeWindow.y_c = y;
  1603. unsafeWindow.defender_c = defender;
  1604. unsafeWindow.shootok_c = shootok;
  1605. if ((x == 0) && (y == 0)) {
  1606. x = cre_collection[attacker]['x'];
  1607. y = cre_collection[attacker]['y'];
  1608. };
  1609. if ((defender > 0) && (cre_collection[defender]['big'])) {
  1610. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  1611. ax++;
  1612. };
  1613. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  1614. ay++;
  1615. };
  1616. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  1617. ax--;
  1618. };
  1619. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  1620. ay--;
  1621. };
  1622. };
  1623. if ((defender > 0) && (cre_collection[defender]['bigx'])) {
  1624. if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
  1625. ax++;
  1626. };
  1627. if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
  1628. ax--;
  1629. };
  1630. };
  1631. if ((defender > 0) && (cre_collection[defender]['bigy'])) {
  1632. if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
  1633. ay++;
  1634. };
  1635. if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
  1636. ay--;
  1637. };
  1638. };
  1639. let dx = x - ax;
  1640. let dy = y - ay;
  1641. l = dx * dx + dy * dy;
  1642. if (movelen == undefined) movelen = 0;
  1643. if (cre_distance !== "") {
  1644. movelen = cre_distance
  1645. l = Math.round(cre_distance * cre_distance)
  1646. if (l > 2) shootok = 1
  1647. else shootok = 0
  1648. if (cre_collection[attacker].shots === 0) shootok = 0
  1649. }
  1650. unsafeWindow.PhysicalModifiers = 1;
  1651. unsafeWindow.PhysicalModifiers *= koef;
  1652. if (cre_collection[attacker]['shadowattack']) l = 0;
  1653.  
  1654. var hera = 0;
  1655. var herd = 0;
  1656. len = unsafeWindow.stage.pole.obj_array.length;
  1657. for (var k1 = 0; k1 < len; k1++) {
  1658. unsafeWindow.k = unsafeWindow.stage.pole.obj_array[k1];
  1659.  
  1660. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[attacker].owner)) hera = unsafeWindow.k;
  1661. if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[defender].owner)) herd = unsafeWindow.k;
  1662. };
  1663. if ((cre_collection[defender]['pirate']) && ((unsafeWindow.magic[defender]['sea']) || (unsafeWindow.gtype == 125) || (unsafeWindow.gtype == 126) || (unsafeWindow.gtype == 133))) {
  1664. unsafeWindow.PhysicalModifiers *= 0.85;
  1665. };
  1666. if (cre_collection[defender]['deadflesh']) {
  1667. unsafeWindow.PhysicalModifiers *= 0.8;
  1668. };
  1669. if (cre_collection[defender]['immaterial']) {
  1670. unsafeWindow.PhysicalModifiers *= 0.65;
  1671. };
  1672. if ((cre_collection[attacker]['oppressionofweak']) && (cre_collection[defender]['level'] == 1)) {
  1673. unsafeWindow.PhysicalModifiers *= 1.5;
  1674. };
  1675. if ((cre_collection[attacker]['fearofstrong']) && (cre_collection[defender]['level'] == 7)) {
  1676. unsafeWindow.PhysicalModifiers *= 0.5;
  1677. };
  1678. if ((hera > 0) && (unsafeWindow.magic[hera]['bna'])) {
  1679. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[hera]['bna']['effect'] / 100);
  1680. if ((cre_collection[defender]['mechanical']) && (unsafeWindow.magic[hera]['MEC'])) {
  1681. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['MEC']['effect'] / 100;
  1682. };
  1683. if ((cre_collection[attacker]['mechanical']) && (unsafeWindow.magic[hera]['mch'])) {
  1684. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['mch']['effect'] / 100;
  1685. };
  1686. };
  1687. if ((cre_collection[defender]['building']) && (!cre_collection[attacker]['siegewalls'])) {
  1688. unsafeWindow.PhysicalModifiers *= 0.05;
  1689. };
  1690. if ((defender > 0) && (cre_collection[attacker]['cruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  1691. unsafeWindow.PhysicalModifiers *= 1.15;
  1692. };
  1693. if ((defender > 0) && (cre_collection[attacker]['morecruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
  1694. unsafeWindow.PhysicalModifiers *= 1.3;
  1695. };
  1696. if ((cre_collection[attacker]['giantkiller']) && (cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 2;
  1697. if ((cre_collection[attacker]['pygmykiller']) && (!cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 1.33;
  1698. if (cre_collection[attacker]['stormstrike']) unsafeWindow.PhysicalModifiers *= 2;
  1699. if ((cre_collection[attacker]['undeadkiller']) && (cre_collection[defender]['undead'])) unsafeWindow.PhysicalModifiers *= 1.5;
  1700. if ((cre_collection[attacker]['pirate']) && (unsafeWindow.magic[defender]['blb'])) unsafeWindow.PhysicalModifiers *= 1.5;
  1701. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.magic[attacker]['zat'])) {
  1702. unsafeWindow.PhysicalModifiers *= 1.15;
  1703. };
  1704. if ((herd > 0) && (unsafeWindow.magic[herd]['bnd'])) {
  1705. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers / (1 + unsafeWindow.magic[herd]['bnd']['effect'] / 100);
  1706. };
  1707. if ((herd > 0) && (unsafeWindow.magic[herd]['fld'])) {
  1708. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[herd]['fld']['effect'] / 100);
  1709. };
  1710. if ((herd > 0) && (unsafeWindow.magic[herd]['rcd']) && (monster_race[cre_collection[attacker]['id']] == unsafeWindow.magic[herd]['rcd']['effect'])) {
  1711. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.93;
  1712. };
  1713. if (unsafeWindow.magic[attacker]['prp']) {
  1714. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[attacker]['prp']['effect'] / 100);
  1715. };
  1716. if (unsafeWindow.magic[defender]['sta']) {
  1717. unsafeWindow.PhysicalModifiers *= 0.5;
  1718. };
  1719. if ((unsafeWindow.magic[attacker]['chd']) && (cre_collection[unsafeWindow.magic[attacker]['chd']['effect']]['nownumber'] > 0) && (unsafeWindow.magic[attacker]['chd']['effect'] != defender)) {
  1720. unsafeWindow.PhysicalModifiers *= 0.55;
  1721. };
  1722. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.checkmembrane(defender);
  1723. if (!cre_collection[attacker]['hero']) {
  1724. if ((l <= 2 || shootok === 0) && (cre_collection[attacker]['shooter']) && (!cre_collection[attacker]['nopenalty']) && (!cre_collection[attacker]['warmachine'])) {
  1725. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1726. };
  1727. if ((l > 2) && (cre_collection[attacker]['rangepenalty'])) {
  1728. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1729. };
  1730. unsafeWindow.rangemod = 1;
  1731. 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))))) {
  1732. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1733. unsafeWindow.rangemod = 0.5;
  1734. };
  1735. 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))) {
  1736. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1737. unsafeWindow.rangemod *= 0.5;
  1738. };
  1739. };
  1740. var _PERK_ARCHERY = 11;
  1741. var _PERK_EVASION = 22;
  1742. 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'))) {
  1743. if (cre_collection[defender]['dodge'])
  1744. unsafeWindow.PhysicalModifiers *= 0.5;
  1745. if (cre_collection[defender]['brittle'])
  1746. unsafeWindow.PhysicalModifiers *= 1.25;
  1747. };
  1748. if ((shootok === 1) && (!cre_collection[attacker]['hero']) && (cre_collection[attacker]['shooter'])) {
  1749. if (unsafeWindow.isperk(attacker, _PERK_ARCHERY)) unsafeWindow.PhysicalModifiers *= 1.2;
  1750. if (unsafeWindow.isperk(defender, _PERK_EVASION)) unsafeWindow.PhysicalModifiers *= 0.8;
  1751. if ((!cre_collection[defender]['lshield']) && (unsafeWindow.stage.pole.shieldother(defender))) {
  1752. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  1753. };
  1754. if ((cre_collection[defender]['lshield']) || (cre_collection[defender]['hollowbones'])) {
  1755. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
  1756. };
  1757. if (cre_collection[defender]['diamondarmor']) {
  1758. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.1;
  1759. };
  1760. if (cre_collection[defender]['shielded']) {
  1761. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
  1762. };
  1763. if (cre_collection[defender]['unprotectedtarget']) {
  1764. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 1.25;
  1765. };
  1766. if (unsafeWindow.magic[defender]['dfm']) {
  1767. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[defender]['dfm']['effect'] / 100);
  1768. };
  1769. if (unsafeWindow.magic[attacker]['cnf']) {
  1770. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[attacker]['cnf']['effect'] / 100);
  1771. };
  1772.  
  1773. if (hera > 0) {
  1774. if (unsafeWindow.magic[hera]['sat']) {
  1775. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[hera]['sat']['effect']) / 100;
  1776. };
  1777. };
  1778. };
  1779. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_BLESS))) {
  1780. unsafeWindow.PhysicalModifiers *= 1.04;
  1781. };
  1782. let o = cre_collection[attacker]['owner'];
  1783. if (unsafeWindow.magic[defender]['mf' + o]) {
  1784. unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[defender]['mf' + o]['effect'] / 100;
  1785. };
  1786. if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_FERVOR))) {
  1787. unsafeWindow.PhysicalModifiers *= 1.03;
  1788. };
  1789. if (hera > 0) {
  1790. var h = hera;
  1791. if ((unsafeWindow.magic[h]['nut']) && ((plid2 == -2) || (ohotnik_set_neutral()))) {
  1792. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['nut']['effect']) / 100;
  1793. };
  1794. if ((unsafeWindow.magic[h]['mle']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1) || cre_collection[attacker].shots == 0)) {
  1795. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['mle']['effect']) / 100;
  1796. };
  1797. if (unsafeWindow.magic[attacker]['fbd']) {
  1798. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + Math.floor(unsafeWindow.magic[attacker]['fbd']['effect'] / 10)) / 100;
  1799. };
  1800. };
  1801. let leap_atk_bonus, leap_distance = 0;
  1802.  
  1803. if (cre_collection[attacker].leap && l >= 4) {
  1804. leap_distance = cre_distance ? cre_distance : Math.min((movelen - 1) * 2, Math.round(Math.sqrt(l)));
  1805. leap_atk_bonus = cre_collection[attacker].attack * (1 + leap_distance * 0.1) - cre_collection[attacker].attack
  1806. cre_collection[attacker]['attackaddon'] += leap_atk_bonus
  1807. }
  1808. unsafeWindow.monatt = cre_collection[attacker]['attack'] + cre_collection[attacker]['attackaddon'] + cre_collection[attacker]['rageattack'];
  1809. if ((defender > 0) && (cre_collection[attacker]['giantslayer']) && (cre_collection[defender]['big'])) unsafeWindow.monatt += 4;
  1810. if ((!cre_collection[attacker]['undead']) && (!cre_collection[attacker]['hero']) && (!cre_collection[attacker]['perseverance'])) {
  1811. unsafeWindow.frig2 = false;
  1812. unsafeWindow.i = attacker;
  1813. var bigx = cre_collection[i]['big'];
  1814. var bigy = cre_collection[i]['big'];
  1815. if (cre_collection[i]['bigx']) bigx = 1;
  1816. if (cre_collection[i]['bigy']) bigy = 1;
  1817. unsafeWindow.xd = cre_collection[i]['x'];
  1818. unsafeWindow.yd = cre_collection[i]['y'];
  1819. for (var xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  1820. for (var yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  1821. 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)) {
  1822. unsafeWindow.monatt -= 4;
  1823. unsafeWindow.frig2 = true;
  1824. };
  1825. };
  1826. };
  1827. };
  1828.  
  1829. if ((unsafeWindow.magic[attacker]['bsr']) || (unsafeWindow.magic[attacker]['rof'])) {
  1830. unsafeWindow.monatt += Math.floor((cre_collection[attacker]['defence'] + cre_collection[attacker]['defenceaddon'] + cre_collection[attacker]['ragedefence']) * cre_collection[attacker]['defencemodifier']);
  1831. };
  1832. if (herd > 0) {
  1833. h = herd;
  1834. if ((unsafeWindow.magic[h]['mld']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1) || cre_collection[attacker].shots == 0)) {
  1835. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['mld']['effect']) / 100;
  1836. };
  1837. if ((unsafeWindow.magic[h]['_ia']) && (!cre_collection[attacker]['perseverance'])) {
  1838. unsafeWindow.monatt *= (1 - unsafeWindow.magic[h]['_ia']['effect'] / 100);
  1839. };
  1840. if ((!cre_collection[attacker]['hero']) && (cre_collection[attacker].shooter) && (cre_collection[attacker].shots != 0) && (unsafeWindow.magic[h]['msk']) && shootok == 1) {
  1841. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['msk']['effect']) / 100;
  1842. };
  1843. };
  1844. unsafeWindow.defadd = 0;
  1845. if (cre_collection[defender]['agility']) {
  1846. if (!unsafeWindow.magic[defender]['agl']) unsafeWindow.defadd = cre_collection[defender]['speed'] * 2;
  1847. };
  1848. if ((cre_collection[defender]['spirit']) && (!unsafeWindow.magic[defender]['spi'])) {
  1849. unsafeWindow.PhysicalModifiers *= 0.5;
  1850. };
  1851. if ((cre_collection[attacker]['rageagainsttheliving']) && (cre_collection[defender]['alive'])) {
  1852. unsafeWindow.PhysicalModifiers *= 1.3;
  1853. };
  1854. if ((cre_collection[defender]['defensivestance']) && (!unsafeWindow.magic[defender]['mvd'])) {
  1855. unsafeWindow.defadd += 5;
  1856. };
  1857. if ((!cre_collection[defender]['undead']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor'])) {
  1858. unsafeWindow.frig2 = false;
  1859. unsafeWindow.i = defender;
  1860. bigx = cre_collection[i]['big'];
  1861. bigy = cre_collection[i]['big'];
  1862. if (cre_collection[i]['bigx']) bigx = 1;
  1863. if (cre_collection[i]['bigy']) bigy = 1;
  1864. unsafeWindow.xd = cre_collection[i]['x'];
  1865. unsafeWindow.yd = cre_collection[i]['y'];
  1866. for (let xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
  1867. for (let yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
  1868. 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)) {
  1869. unsafeWindow.defadd -= 4;
  1870. unsafeWindow.frig2 = true;
  1871. };
  1872. };
  1873. };
  1874. };
  1875. if ((attacker > 0) && (cre_collection[defender]['giantslayer']) && (cre_collection[attacker]['big'])) unsafeWindow.defadd += 4;
  1876. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + unsafeWindow.defadd + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  1877. if (unsafeWindow.magic[defender]['bsr']) {
  1878. unsafeWindow.mondef = 0;
  1879. };
  1880.  
  1881. if ((cre_collection[attacker]['preciseshot']) && (l > 2) && (l <= 9) && (unsafeWindow.rangemod >= 1)) {
  1882. unsafeWindow.mondef = 0;
  1883. };
  1884. if ((cre_collection[attacker]['ignoredefence'])) {
  1885. unsafeWindow.mondef *= (1 - cre_collection[attacker]['ignoredefence'] / 100);
  1886. };
  1887. if (cre_collection[attacker]['crushingleadership']) {
  1888. var morale_delta = unsafeWindow.stage.pole.getmorale(attacker) - unsafeWindow.stage.pole.getmorale(defender);
  1889. if (morale_delta > 0) {
  1890. unsafeWindow.mondef *= Math.max(0, 1 - morale_delta / 10);
  1891. };
  1892. };
  1893. if (cre_collection[attacker]['sacredweapon']) {
  1894. var dark_count = get_dark_count(defender);
  1895. if (dark_count > 0) {
  1896. unsafeWindow.mondef *= Math.max(0, 1 - 0.15 * dark_count);
  1897. };
  1898. };
  1899. if (unsafeWindow.isperk(attacker, _PERK_PIERCING_LUCK)) {
  1900. unsafeWindow.mondef *= 1 - Math.max(0, 0.025 * (cre_collection[attacker]['luck'] + cre_collection[attacker]['luckaddon']));
  1901. };
  1902. if ((cre_collection[defender]['ignoreattack'])) {
  1903. unsafeWindow.monatt *= (1 - cre_collection[defender]['ignoreattack'] / 100);
  1904. };
  1905. if ((cre_collection[attacker]['ridercharge']) && (movelen > 0)) {
  1906. unsafeWindow.mondef = unsafeWindow.mondef * (5 - movelen) / 5;
  1907. };
  1908. if ((cre_collection[attacker]['forcearrow']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  1909. unsafeWindow.mondef *= 0.8;
  1910. };
  1911. if ((cre_collection[attacker]['armorpiercing']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
  1912. unsafeWindow.mondef *= 0.5;
  1913. };
  1914. if (cre_collection[defender]['shroudofdarkness']) {
  1915. unsafeWindow.PhysicalModifiers *= Math.max(0, 1 - 0.15 * get_dark_count(defender));
  1916. };
  1917. if (cre_collection[attacker]['tasteofdarkness']) {
  1918. unsafeWindow.PhysicalModifiers *= 1 + get_dark_count(defender) * 0.12;
  1919. };
  1920. if ((cre_collection[attacker]['jousting']) && (movelen > 0)) {
  1921. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.05 * movelen);
  1922. };
  1923. if (((cre_collection[attacker]['blindingcharge']) || (cre_collection[attacker]['charge'])) && (movelen > 0)) {
  1924. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.1 * movelen);
  1925. };
  1926. if ((cre_collection[defender]['shieldwall']) && (movelen > 0)) {
  1927. unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * Math.max(0.1, 1 - 0.1 * movelen);
  1928. };
  1929. if ((unsafeWindow.magic[defender]['enc']) && (unsafeWindow.magic[defender]['enc']['effect'] == 1)) {
  1930. unsafeWindow.PhysicalModifiers *= 0.5;
  1931. };
  1932. if ((cre_collection[attacker]['safeposition']) && (movelen == 0)) {
  1933. unsafeWindow.PhysicalModifiers *= 1.5;
  1934. };
  1935. if ((cre_collection[attacker]['agilesteed']) && (movelen > 0)) {
  1936. unsafeWindow.PhysicalModifiers *= 1 - 0.05 * movelen;
  1937. };
  1938. if (unsafeWindow.mondef < 0) {
  1939. unsafeWindow.mondef = 0;
  1940. };
  1941.  
  1942. unsafeWindow.air = 0;
  1943. unsafeWindow.fire = 0;
  1944. unsafeWindow.water = 0;
  1945. unsafeWindow.earth = 0;
  1946. if ((hera > 0) && (!cre_collection[attacker]['taran'])) {
  1947. h = hera;
  1948. if (unsafeWindow.magic[h]['_id']) {
  1949. unsafeWindow.mondef *= (1 - unsafeWindow.magic[h]['_id']['effect'] / 100);
  1950. };
  1951. if (unsafeWindow.magic[h]['_aa']) {
  1952. unsafeWindow.air = unsafeWindow.magic[h]['_aa']['effect'] / 100;
  1953. };
  1954. if (unsafeWindow.magic[h]['_af']) {
  1955. unsafeWindow.fire = unsafeWindow.magic[h]['_af']['effect'] / 100;
  1956. };
  1957. if (unsafeWindow.magic[h]['_aw']) {
  1958. unsafeWindow.water = unsafeWindow.magic[h]['_aw']['effect'] / 100;
  1959. };
  1960. if (unsafeWindow.magic[h]['_ae']) {
  1961. unsafeWindow.earth = unsafeWindow.magic[h]['_ae']['effect'] / 100;
  1962. };
  1963. };
  1964. if ((cre_collection[defender]['armoured']) || (cre_collection[defender]['organicarmor'])) {
  1965. unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
  1966. };
  1967. if (unsafeWindow.monatt < 0) {
  1968. unsafeWindow.monatt = 0;
  1969. };
  1970. if (unsafeWindow.monatt > unsafeWindow.mondef) {
  1971. unsafeWindow.AttackDefenseModifier = 1 + (unsafeWindow.monatt - unsafeWindow.mondef) * 0.05;
  1972. } else {
  1973. unsafeWindow.AttackDefenseModifier = 1 / (1 + (unsafeWindow.mondef - unsafeWindow.monatt) * 0.05);
  1974. };
  1975. if (cre_collection[attacker]['hero']) {
  1976. unsafeWindow.AttackDefenseModifier = 1;
  1977. };
  1978. var _PERK_ATTACK1 = 8;
  1979. var _PERK_ATTACK2 = 9;
  1980. var _PERK_ATTACK3 = 10;
  1981. var _PERK_DEFENSE1 = 19;
  1982. var _PERK_DEFENSE2 = 20;
  1983. var _PERK_DEFENSE3 = 21;
  1984.  
  1985. if ((!cre_collection[attacker]['hero']) && ((cre_collection[attacker].shooter && shootok == 0) || (cre_collection[attacker].shooter != 1))) {
  1986. if (unsafeWindow.isperk(attacker, _PERK_ATTACK3)) {
  1987. unsafeWindow.PhysicalModifiers *= 1.3;
  1988. } else {
  1989. if (unsafeWindow.isperk(attacker, _PERK_ATTACK2)) {
  1990. unsafeWindow.PhysicalModifiers *= 1.2;
  1991. } else
  1992. if (unsafeWindow.isperk(attacker, _PERK_ATTACK1)) unsafeWindow.PhysicalModifiers *= 1.1;
  1993. };
  1994. if (unsafeWindow.isperk(defender, _PERK_DEFENSE3)) {
  1995. unsafeWindow.PhysicalModifiers *= 0.7;
  1996. } else {
  1997. if (unsafeWindow.isperk(defender, _PERK_DEFENSE2)) {
  1998. unsafeWindow.PhysicalModifiers *= 0.8;
  1999. } else {
  2000. if (unsafeWindow.isperk(defender, _PERK_DEFENSE1)) unsafeWindow.PhysicalModifiers *= 0.9;
  2001. };
  2002. };
  2003. };
  2004. if ((cre_collection[attacker]['siegewalls']) && (cre_collection[defender]['stone'])) {
  2005. unsafeWindow.PhysicalModifiers *= 10;
  2006. };
  2007. var _PERK_COLD_STEEL = 14;
  2008. var _PERK_FIERY_WRATH = 101;
  2009. var _PERK_HELLFIRE_AURA = 123;
  2010. var _PERK_RETRIBUTION = 16;
  2011.  
  2012. if (unsafeWindow.isperk(attacker, _PERK_COLD_STEEL)) unsafeWindow.water = 1 - (1 - unsafeWindow.water) * (0.9);
  2013. if (unsafeWindow.isperk(attacker, _PERK_FIERY_WRATH)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.85);
  2014. if (unsafeWindow.isperk(attacker, _PERK_HELLFIRE_AURA)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.95);
  2015.  
  2016. if (unsafeWindow.magic[attacker]['cre']) {
  2017. unsafeWindow.air = 1 - (1 - unsafeWindow.air) * (1 - unsafeWindow.magic[attacker]['cre']['effect'] / 100);
  2018. };
  2019.  
  2020. if (unsafeWindow.isperk(attacker, _PERK_RETRIBUTION)) unsafeWindow.PhysicalModifiers *= (1 + Math.min(Math.max(unsafeWindow.stage.pole.getmorale(attacker, x, y), 0), 5) / 20);
  2021. 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;
  2022. unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.magicmod(attacker, defender, unsafeWindow.fire, unsafeWindow.air, unsafeWindow.water, unsafeWindow.earth, 0.1);
  2023. if ((cre_collection[attacker]['bloodfrenzy']) && (unsafeWindow.magic[defender]['fd1'])) {
  2024. unsafeWindow.PhysicalModifiers *= 1.3;
  2025. };
  2026. unsafeWindow.UmelkaModifiers = 1;
  2027.  
  2028. if ((umelka[cre_collection[attacker]['owner']][0] > 0) && (umelka[cre_collection[defender]['owner']][0] > 0)) {
  2029. unsafeWindow.k = umelka[cre_collection[attacker]['owner']][0];
  2030. if ((unsafeWindow.k > 0) && (unsafeWindow.k < 11)) {
  2031. let j = umelka[cre_collection[defender]['owner']][k];
  2032. unsafeWindow.UmelkaModifiers = 1 - j * 0.03;
  2033. };
  2034. };
  2035. unsafeWindow.NumCreatures = cre_collection[attacker]['nownumber'];
  2036. let tsc = 0;
  2037.  
  2038. bigx = cre_collection[defender]['big'];
  2039. bigy = cre_collection[defender]['big'];
  2040. if (cre_collection[defender]['bigx']) bigx = 1;
  2041. if (cre_collection[defender]['bigy']) bigy = 1;
  2042. for (var xs = cre_collection[defender]['x'] - 1; xs <= cre_collection[defender]['x'] + 1 + bigx; xs++) {
  2043. for (var ys = cre_collection[defender]['y'] - 1; ys <= cre_collection[defender]['y'] + 1 + bigy; ys++) {
  2044. 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'])) {
  2045. tsc++;
  2046. };
  2047. };
  2048. };
  2049.  
  2050.  
  2051. unsafeWindow.PhysicalModifiers /= (tsc + 1);
  2052.  
  2053. var minmag = 0;
  2054. var maxmag = 0;
  2055. if ((inuse == 'lep') && (cre_collection[attacker]['crashingleap'])) {
  2056. unsafeWindow.Totalmagicdamage = 0;
  2057. cre_collection[defender]['attacked'] = 1;
  2058. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 4, 'cold', '', 0, 0, 0);
  2059. minmag = unsafeWindow.Totalmagicdamage;
  2060. unsafeWindow.Totalmagicdamage = 0;
  2061. cre_collection[defender]['attacked'] = 1;
  2062. unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 6, 'cold', '', 0, 0, 0);
  2063. maxmag = unsafeWindow.Totalmagicdamage;
  2064. };
  2065.  
  2066. 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'];
  2067. 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'];
  2068. h = hera;
  2069. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['BLS']) && (unsafeWindow.magic[h]['BLS']['effect'] > 0)) unsafeWindow.mindam = unsafeWindow.maxdam;
  2070. if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['CRS']) && (unsafeWindow.magic[h]['CRS']['effect'] > 0)) unsafeWindow.maxdam = unsafeWindow.mindam;
  2071. if ((cre_collection[attacker]['taran']) && (cre_collection[defender]['stone'])) {
  2072. h = hera;
  2073. unsafeWindow.mindam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 200 * cre_collection[attacker]['mindam']);
  2074. unsafeWindow.maxdam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 400 * cre_collection[attacker]['maxdam']);
  2075. };
  2076. if (cre_collection[attacker]['accuracy']) unsafeWindow.mindam = unsafeWindow.maxdam;
  2077. unsafeWindow.BaseDamage = unsafeWindow.mindam;
  2078. unsafeWindow.PhysicalDamage = unsafeWindow.NumCreatures * unsafeWindow.BaseDamage * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + minmag;
  2079. unsafeWindow.PhysicalDamage2 = unsafeWindow.NumCreatures * unsafeWindow.maxdam * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + maxmag;
  2080. if ((cre_collection[attacker]['deathstrike']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  2081. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage) {
  2082. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage % cre_collection[defender]['maxhealth'];
  2083. };
  2084. if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage2) {
  2085. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage2 % cre_collection[defender]['maxhealth'];
  2086. };
  2087. };
  2088.  
  2089. if (cre_collection[attacker]['bladeofslaughter']) {
  2090. unsafeWindow.PhysicalDamage += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  2091. unsafeWindow.PhysicalDamage2 += Math.min(500, cre_collection[defender]['nownumber'] * 2);
  2092. };
  2093. if (unsafeWindow.magic[attacker]['brk']) {
  2094. unsafeWindow.PhysicalDamage *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  2095. unsafeWindow.PhysicalDamage2 *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
  2096. };
  2097. if (unsafeWindow.PhysicalDamage < 1) {
  2098. unsafeWindow.PhysicalDamage = 1;
  2099. };
  2100. if (unsafeWindow.PhysicalDamage2 < 1) {
  2101. unsafeWindow.PhysicalDamage2 = 1;
  2102. };
  2103. if ((cre_collection[attacker]['magicattack']) && (unsafeWindow.l > 2) && (unsafeWindow.stage.pole.issomething(defender, 'dampenmagic'))) unsafeWindow.PhysicalDamage = 0;
  2104. if (unsafeWindow.magic[defender]['rag']) {
  2105. unsafeWindow.PhysicalDamage = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage);
  2106. unsafeWindow.PhysicalDamage2 = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage2);
  2107. };
  2108. if ((cre_collection[attacker]['vorpalsword']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
  2109. unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'];
  2110. unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'];
  2111. };
  2112.  
  2113. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage);
  2114. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2);
  2115. if (cre_collection[defender]['pleasureinpain']) {
  2116. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.9);
  2117. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.9);
  2118. };
  2119. if (cre_collection[defender]['raptureinagony']) {
  2120. unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.8);
  2121. unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.8);
  2122. };
  2123. var totalh = (cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'];
  2124. unsafeWindow.Uronkills = Math.floor(Math.min(unsafeWindow.PhysicalDamage, totalh) / cre_collection[defender]['maxhealth']);
  2125. unsafeWindow.Uronkills2 = Math.floor(Math.min(unsafeWindow.PhysicalDamage2, totalh) / cre_collection[defender]['maxhealth']);
  2126. var nowhealth = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage, totalh) - unsafeWindow.Uronkills * cre_collection[defender]['maxhealth']);
  2127. var nowhealth2 = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage2, totalh) - unsafeWindow.Uronkills2 * cre_collection[defender]['maxhealth']);
  2128. if (nowhealth <= 0) unsafeWindow.Uronkills++;
  2129. if (nowhealth2 <= 0) unsafeWindow.Uronkills2++;
  2130. unsafeWindow.tUronkills += unsafeWindow.Uronkills;
  2131. unsafeWindow.tUronkills2 += unsafeWindow.Uronkills2;
  2132. unsafeWindow.tPhysicalDamage += unsafeWindow.PhysicalDamage;
  2133. unsafeWindow.tPhysicalDamage2 += unsafeWindow.PhysicalDamage2;
  2134. if (![0, 1].includes(leap_distance)) cre_collection[attacker].attackaddon -= leap_atk_bonus;
  2135. let leap_display_distance = ""
  2136. if (leap_atk_bonus) leap_display_distance = cre_distance ? "" : leap_distance;
  2137. return { distance: leap_display_distance, leap_atk_bonus: leap_atk_bonus }
  2138. }
  2139.  
  2140. function get_dmg_info(attacker_obj_index, defender_obj_index, koef = 1) {
  2141. let cre_collection = unsafeWindow.stage.pole.obj
  2142. let attacker = cre_collection[attacker_obj_index]
  2143. let defender = cre_collection[defender_obj_index]
  2144. let dmg_dict = attackmonster(attacker_obj_index, attacker.x, attacker.y, defender.x, defender.y, defender_obj_index, GM_getValue("cre_distance"), 1, koef);
  2145. let min_damage = unsafeWindow.PhysicalDamage
  2146. let max_damage = unsafeWindow.PhysicalDamage2
  2147. let min_killed, max_killed;
  2148. if (min_damage % defender.maxhealth >= defender.nowhealth) min_killed = Math.floor(min_damage / defender.maxhealth) + 1
  2149. else min_killed = Math.floor(min_damage / defender.maxhealth)
  2150. if (max_damage % defender.maxhealth >= defender.nowhealth) max_killed = Math.floor(max_damage / defender.maxhealth) + 1
  2151. else max_killed = Math.floor(max_damage / defender.maxhealth)
  2152. return { min: min_damage, max: max_damage, min_killed: min_killed, max_killed: max_killed, distance: dmg_dict.distance }
  2153. }
  2154.  
  2155. let defender_obj_id = 0
  2156. let selected_id = 0
  2157.  
  2158. function refresh() {
  2159. isOpen = true
  2160. let cre_collection = unsafeWindow.stage.pole.obj;
  2161. if (cre_distance_on) {
  2162. cre_distance_div.style.display = "inline";
  2163. cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
  2164. }
  2165. set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc], "inline")
  2166.  
  2167. refresh_button.innerHTML = "Обновить"
  2168. let cre_list = Object.values(cre_collection);
  2169. cre_list.sort(function(a, b) {
  2170. return a.obj_index - b.obj_index;
  2171. });
  2172. dmg_list_container.innerHTML = "";
  2173. [...select.children].forEach(child => child.remove())
  2174. let found_defender = false
  2175. cre_list.forEach(defender => {
  2176. if (defender.nownumber > 0 && defender.nametxt != "" && defender.side == chosen.side && defender.hero === undefined) {
  2177. let option_id = `cre_no${cre_list.indexOf(defender)}`;
  2178. select.insertAdjacentHTML("beforeend", `<option id = "${option_id}" value = "${defender.obj_index}">${defender.nametxt} [${defender.nownumber}] </option>`)
  2179. if (!found_defender) {
  2180. if (`${defender.obj_index}` == chosen.creature) found_defender = true
  2181. defender_obj_id = defender.obj_index
  2182. selected_id = [...select.children].indexOf(select.lastChild)
  2183. }
  2184. }
  2185. });
  2186.  
  2187. dmg_list_container.insertAdjacentHTML("beforeend", `<div id = "chosen_cre_heading" style="display:inline; background-color: ${physCalcColor}">
  2188. <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>
  2189. </div>`)
  2190. cre_list.forEach(attacker => {
  2191. if (attacker.side == -chosen.side && attacker.nownumber > 0 && attacker.nametxt != "") {
  2192. let dmg = get_dmg_info(attacker.obj_index, defender_obj_id)
  2193. let practical_overall_hp;
  2194. if (cre_collection[defender_obj_id].attack > attacker.defence) {
  2195. practical_overall_hp = attacker.maxhealth * attacker.nownumber / (1 + 0.05 * Math.abs(cre_collection[defender_obj_id].attack - attacker.defence))
  2196. } else {
  2197. practical_overall_hp = attacker.maxhealth * attacker.nownumber * (1 + 0.05 * Math.abs(cre_collection[defender_obj_id].attack - attacker.defence))
  2198. }
  2199. let row_id = `row_no${cre_list.indexOf(attacker)}`
  2200. let koef_string = `(коэф. урона <b>${( ((dmg.max + dmg.min) / 2) / practical_overall_hp ).toFixed(2)}</b>)`;
  2201. 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>`);
  2202. dmg_list_container.insertAdjacentHTML("beforeend", calcHellFireHTML(attacker, cre_collection[defender_obj_id], cre_collection, dmg));
  2203. dmg_list_container.insertAdjacentHTML("beforeend", calcStormHTML(attacker, cre_collection[defender_obj_id]));
  2204.  
  2205. mag_damage_on && lastturn > 0 && dmg_list_container.insertAdjacentHTML("beforeend", calcMagicHTML(attacker, cre_collection[defender_obj_id], cre_collection, dmg));
  2206. }
  2207. })
  2208. select.options.item(selected_id).selected = true
  2209. }
  2210. initGates();