battle_damage_tooltip

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

目前為 2023-05-02 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         battle_damage_tooltip
// @namespace    http://tampermonkey.net/
// @version      0.9.8
// @description  Скрины с функционалом ниже. 1.) Показывает урон всех стеков одной стороны по одному выбранному стеку второй стороны. 2.) Если навести курсор на 1 существо, нажать 'e' (русская 'у'), сделать то же самое со вторым, то в чате появится урон первого по второму. Доп. настройки в настройках боя.
// @author       Something begins
// @license      None
// @match       https://www.heroeswm.ru/war*
// @match       https://my.lordswm.com/war*
// @match       https://www.lordswm.com/war*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_setValue
// @grant        GM_getValue
// @grant unsafeWindow
// ==/UserScript==
// Странные способы в некоторых местах обусловлены конфликтом со скриптом battleHelper от omne
let outer_chat = document.getElementById("chat_format");
outer_chat.insertAdjacentHTML("beforeend", `
<div id="cre_distance_div" style="display: none"></div>
<div id="individual_calc"></div>
<div id="dmg_list_container"></div>
<br>
<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>
<select style="display : none; background-color: #333; color: white; margin: 10px" id="choose_cre"></select>
<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>
<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> `)
let calc_x, calc_y;
let last_individual_calc = {}
let isOpen = false
let ini_weight = 10;
let chosen = {side: 1, creature: "Высшие вампиры", afterSideSwitchCre: {"-1": "", "1": ""}}
let chat = document.getElementById("chat_inside");
let select = document.getElementById("choose_cre")
let refresh_button = document.getElementById("dmg_list_refresh")
let side_button = document.getElementById("change_side")
let collapse_button = document.getElementById("collapse")
let individual_calc = document.querySelector("#individual_calc")
let cre_distance_div = document.querySelector("#cre_distance_div")
const settings_panel = document.querySelector("#webgl_settings_whole")
let dmg_list_container = document.querySelector("#dmg_list_container")
cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`

// ========= utils ============
function get_GM_value_if_exists(GM_key, default_value){
    const GM_value = GM_getValue(GM_key)
    return GM_value!=undefined ? GM_value : default_value;
}
function individual_calc_innerHTML(atk_obj_index, def_obj_index){
    if (atk_obj_index === undefined || def_obj_index === undefined) return ""
    let cre_collection = unsafeWindow.stage.pole.obj
    let attacker = cre_collection[atk_obj_index];
    let defender = cre_collection[def_obj_index];
    let dmg = get_dmg_info(atk_obj_index, def_obj_index)
    last_individual_calc.atk_obj_index = atk_obj_index; last_individual_calc.def_obj_index = def_obj_index;
    individual_calc.style.backgroundColor = "#000066"
    return ` <div id="individual_cre_heading" style="display:inline; background-color: #000066">
  <span>Урон <br>
  </span>
  <span>
    <b>${attacker.nametxt}</b> [${attacker.nownumber}] по <b>${defender.nametxt}</b> [${defender.nownumber}]: <br>
    <br>
  </span>
</div>
<p id="${0}" style=" background-color: #000066">
  <span style=color:#bfbfbf"></span>
  <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>)
</p>
<br>`
}
function paint_coords(x,y, color){
    let tile = shado[x + y*defxn]
    if (tile == undefined) return
    tile.stroke(color)
    tile.fill(color)
    set_visible(tile,1)

    setTimeout(()=>{
        tile.fill(null)
        set_visible(tile,0)
    },2077)
}
const observer = new MutationObserver((mutationsList, observer) => {
    for(const mutation of mutationsList) {
        if (mutation.type === 'childList') {
            for (const addedNode of mutation.addedNodes) {
                if (addedNode.classList && addedNode.classList.contains('cont') || ["B", "BR"].includes(addedNode.tagName)) {
                    battleHelper_display(battleHelper_on)
                }
            }
        }
    }
});

function GM_toggle_boolean(GM_key, boolean){
    boolean = !boolean
    GM_setValue(GM_key, boolean);
    return boolean
}
function set_Display(element_arr, displayProperty){
    element_arr.forEach(element=>{
        if (element == null) return
        element.style.display = displayProperty
    })
}
function readjust_elements(){
    chat = document.getElementById("chat_inside");
    select = document.getElementById("choose_cre")
    refresh_button = document.getElementById("dmg_list_refresh")
    side_button = document.getElementById("change_side")
    collapse_button = document.getElementById("collapse")
    dmg_list_container = document.querySelector("#dmg_list_container")
    individual_calc = document.querySelector("#individual_calc")
    cre_distance_div = document.querySelector("#cre_distance_div")
}
// -----------------------------------
// =========   Настройки ============

let cre_distance = get_GM_value_if_exists('cre_distance', "")
let cre_distance_on = get_GM_value_if_exists('cre_distance_on', false)
let coeff_on = get_GM_value_if_exists('GM_coeff_on', false)
let battleHelper_on = get_GM_value_if_exists('battleHelper_on', true)
const new_settings = `
<style>
  .tooltip {
    position: relative;
    display: inline-block;
    text-size: 150%;
    color: brown;
    text-decoration: underline;
  }

  .tooltip .tooltiptext {
    visibility: hidden;
    position: absolute;
    bottom: 100%;
    left: 50%;
    width: 5000%;
    transform: translateX(-30%);
    padding: 5px;
    background-color: #555;
    color: #fff;
    border-radius: 6px;
    word-wrap: break-word;
  }

  .tooltip:hover .tooltiptext {
    visibility: visible;
  }
</style>
<div class="info_row">
  <label class="checkbox_container">коэф. урона <span class="tooltip">? <span class="tooltiptext">отношение урон/хп (т.е. у кого больше всех коэф., с того выгоднее начинать. <br>Работает в списке уронов если нажать на "Открыть" в чате)</span>
  </span>
    <input type="checkbox" checked="true" id="coeff_on">
    <span class="checkbox_checkmark"></span>
  </label>
</div>
<div class="info_row">
  <label class="checkbox_container">battleHelper в чате <span class="tooltip">? <span class="tooltiptext">выключает или включает начальное распределение АТБ шкалы от omne</span>
  </span> <input type="checkbox" checked="true" id="battleHelper_on">
    <span class="checkbox_checkmark"></span>
  </label>
</div>
<div class="info_row">
  <label class="checkbox_container">Расстояние между стеками <span class="tooltip">? <span class="tooltiptext">Расстояние между атакующим и защищающимся стеками. Выбирать расстояние стрелочками в текстовом поле снизу. <br>
    Влияет на статус урона стрелка (ближний/дальний урон, кривая/прямая стрела),
     разбег и прочие абилки, зависящие от расстояния. <br> Если выставить "Расстояние: 1", то стрелок будет считаться заблокированным.
      Если выставить расстояние больше 1,
       то стрелок будет считаться не заблокированным (даже если рядом с ним вражеское существо). </span>
    </span>
    <input type="checkbox" checked="true" id="cre_distance_on">
    <span class="checkbox_checkmark"></span>
  </label>
  <input type="number" style="width: 4%; margin: 2px 2px 2px 80px" id="cre_distance" onkeydown="return false;" value=${cre_distance}>
</div>
`
settings_panel.insertAdjacentHTML("beforeend", new_settings)

let settings_interval = setInterval(()=>{
    let temp = document.querySelector("#coeff_on")
    if (temp){
        document.querySelector("#coeff_on").checked = coeff_on
        document.querySelector("#battleHelper_on").checked = battleHelper_on
        document.querySelector("#cre_distance_on").checked = cre_distance_on
        clearInterval(settings_interval)
    }
},300)
const distance_counter = document.getElementById("cre_distance");
distance_counter.addEventListener("input", () => {
    if (distance_counter.value < 1) {
        distance_counter.value = 1
        return
    }
    if (!cre_distance_on) return
    GM_setValue('cre_distance', distance_counter.value)
    if (isOpen) refresh()
    individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
    cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
});
document.body.addEventListener('change', function(event) {
    switch (event.target.id){
        case "coeff_on":
            coeff_on = GM_toggle_boolean("coeff_on", coeff_on)
            if (isOpen) refresh()
            break;
        case "battleHelper_on":
            battleHelper_on = GM_toggle_boolean("battleHelper_on", battleHelper_on)
            battleHelper_display(battleHelper_on)
            break
        case "choose_cre":
            chosen.creature = select.value
            refresh()
            break;
        case "cre_distance_on":
            cre_distance_on = GM_toggle_boolean("cre_distance_on", cre_distance_on)
            cre_distance_on ? GM_setValue('cre_distance', distance_counter.value): GM_setValue('cre_distance', "")
            if (cre_distance_on){
                cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
                cre_distance_div.style.display = "inline"
                if (isOpen) refresh()
                individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
            }
            else{
                cre_distance_div.innerHTML = ""
            }
            if (isOpen) refresh()
            individual_calc.innerHTML = individual_calc_innerHTML(last_individual_calc.atk_obj_index, last_individual_calc.def_obj_index)
            break;
    }
});
// -----------------------------------

// =========  battleHelper ============

function battleHelper_display(ifDisplay){
    [...outer_chat.children].forEach(child=>{
        if (["B","BR"].includes(child.tagName) || child.className == "cont"){
            child.style.display = ifDisplay ? "inline" : "none"
        }
    })
    if (ifDisplay){
        if (!outer_chat.innerText.includes("Команда №1")) {
            let br_list = [...outer_chat.children].filter(br_element =>"BR" == br_element.tagName);
            let team_no = 0
            br_list.forEach(br_element=>{
                let index = br_list.indexOf(br_element)
                if (index%2==0 && index != br_list.length-2){
                    team_no++;
                    br_element.insertAdjacentHTML("afterend", `Команда №${team_no}`)
                }
            });
        }
    }
    else {
        const childNodes = outer_chat.childNodes;
        for (let i = 0; i < childNodes.length; i++) {
            const childNode = childNodes[i];
            if (childNode.nodeType === Node.TEXT_NODE) {
                const text = childNode.textContent.trim();
                if (text !== '') {
                    childNode.textContent = '';
                }
            }
        }
    }
}
observer.observe(outer_chat, { childList: true });
setTimeout(function() {
    observer.disconnect();
}, 30000);

// -----------------------------------


document.body.addEventListener('click', function(event) {
    switch(event.target.id){
        case "dmg_list_refresh":
            readjust_elements()
            refresh()
            break
        case "change_side":
            chosen.afterSideSwitchCre[chosen.side] = chosen.creature
            chosen.side = - chosen.side
            chosen.creature = chosen.afterSideSwitchCre[chosen.side]
            refresh()
            break
        case "collapse":
            readjust_elements()
            isOpen = false
            battleHelper_display(battleHelper_on);
            refresh_button.innerHTML = "Открыть";
            set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc, cre_distance_div], "none")
            break
        case "confirm_ins_img":
            observer.observe(outer_chat, { childList: true });
            setTimeout(function() {
                observer.disconnect();
            }, 190000);
    }
})
outer_chat.addEventListener('change', function() {
    chosen.creature = select.value
    refresh()
});

// Урон одного стека по другому по выбору нажатием кнопки E
window.addEventListener("keyup", event => {
    if ((document.querySelector("#chattext") !== document.activeElement) && (document.querySelector("#chattext_classic") !== document.activeElement)) {
        if (["e", "E", "у", "У"].includes(event.key)) {
            let cre_collection = unsafeWindow.stage.pole.obj
            if (mapobj[xr_last+yr_last*defxn] === undefined || cre_collection[mapobj[xr_last+yr_last*defxn]].rock === 1) {
                paint_coords(xr_last,yr_last,"#cccccc")
                return
            }
            if (!calc_x){
                calc_x = xr_last
                calc_y = yr_last
                paint_coords(xr_last,yr_last,"#800000")
            }
            else {
                readjust_elements()
                let atk_obj_index = unsafeWindow.mapobj[calc_x+calc_y*defxn]
                let def_obj_index = unsafeWindow.mapobj[xr_last+yr_last*defxn]
                set_Display([individual_calc, collapse_button], "inline")
                if (cre_distance_on) {
                    cre_distance_div.style.display = "inline";
                    cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
                }
                individual_calc.innerHTML = individual_calc_innerHTML(atk_obj_index, def_obj_index)
                calc_x = calc_y = null
                paint_coords(xr_last,yr_last,"blue")
            }
        }
    }
})


// Родная функция гвд с поправками на переменную l и модификаторами magic[]
function attackmonster(attacker, ax, ay, x, y, defender,cre_distance, shootok, koef, inuse) {
    let cre_collection = unsafeWindow.stage.pole.obj
    var mainattack = 1;
    var ax1 = ax;
    var ay1 = ay;
    if (defender == 1000) return 0;
    if (defender <= 0) return 0;
    if (!cre_collection[defender]) return 0;
    if (cre_collection[defender]['hero']) return 0;
    if (cre_collection[defender]['rock']) return 0;
    if (koef == undefined) koef = 1;
    if (inuse == undefined) inuse = '';
    var len = unsafeWindow.wmap2[y * defxn + x];
    if ((cre_collection[attacker].x == x) && (cre_collection[attacker].y == y)) len = spd;
    shootok = 1;
    function getAdjacentAndDiagonalCoords(x, y) {
        const adjacentAndDiagonalCoords = [];
        adjacentAndDiagonalCoords.push([x + 1, y]);
        adjacentAndDiagonalCoords.push([x - 1, y]);
        adjacentAndDiagonalCoords.push([x, y + 1]);
        adjacentAndDiagonalCoords.push([x, y - 1]);
        adjacentAndDiagonalCoords.push([x + 1, y + 1]);
        adjacentAndDiagonalCoords.push([x - 1, y + 1]);
        adjacentAndDiagonalCoords.push([x + 1, y - 1]);
        adjacentAndDiagonalCoords.push([x - 1, y - 1]);
        return adjacentAndDiagonalCoords;
    }
    let attacker_adjacent_coords = getAdjacentAndDiagonalCoords(stage.pole.obj[attacker].x, stage.pole.obj[attacker].y)
    let enemies_list = Object.values(stage.pole.obj).filter(creature=>creature.side!=stage.pole.obj[attacker].side)
    enemies_list.forEach(enemy=>{
        attacker_adjacent_coords.forEach(coord=>{
            if (coord[0] == enemy.x && coord[1] == enemy.y) shootok = 0
        })
    })

    if (cre_collection[attacker]['big']) {
        if (ax > x) {
            x++;
        };
        if (ay > y) {
            y++;
        };
    };
    if (cre_collection[attacker]['bigx']) {
        if (ax > x) {
            x++;
        };
    };
    if (cre_collection[attacker]['bigy']) {
        if (ay > y) {
            y++;
        };
    };
    var spd = Math.max(0, Math.round((cre_collection[attacker].speed + cre_collection[attacker]['ragespeed'] + cre_collection[attacker]['speedaddon']) * cre_collection[attacker].speedmodifier));
    if (unsafeWindow.magic[attacker]['ent']) {
        spd = 0;
    };
    var movelen = spd - len;
    unsafeWindow.attacker_c = attacker;
    unsafeWindow.ax_c = ax;
    unsafeWindow.ay_c = ay;
    unsafeWindow.x_c = x;
    unsafeWindow.y_c = y;
    unsafeWindow.defender_c = defender;
    unsafeWindow.shootok_c = shootok;
    if ((x == 0) && (y == 0)) {
        x = cre_collection[attacker]['x'];
        y = cre_collection[attacker]['y'];
    };
    if ((defender > 0) && (cre_collection[defender]['big'])) {
        if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
            ax++;
        };
        if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
            ay++;
        };
        if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
            ax--;
        };
        if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
            ay--;
        };
    };
    if ((defender > 0) && (cre_collection[defender]['bigx'])) {
        if ((x - ax > 1) && (ax < x) && (defender == mapobj[ay * defxn + ax + 1])) {
            ax++;
        };
        if ((ax - x > 1) && (ax > x) && (defender == mapobj[ay * defxn + ax - 1])) {
            ax--;
        };
    };
    if ((defender > 0) && (cre_collection[defender]['bigy'])) {
        if ((y - ay > 1) && (ay < y) && (defender == mapobj[(ay + 1) * defxn + ax])) {
            ay++;
        };
        if ((ay - y > 1) && (ay > y) && (defender == mapobj[(ay - 1) * defxn + ax])) {
            ay--;
        };
    };
    let dx = x - ax;
    let dy = y - ay;
    l = dx * dx + dy * dy;
    if (movelen == undefined) movelen = 0;
    if (cre_distance !=="") {
        movelen = cre_distance
        l = Math.round(cre_distance * cre_distance)
        if (l > 2) shootok = 1
        else shootok = 0
    }
    unsafeWindow.PhysicalModifiers = 1;
    unsafeWindow.PhysicalModifiers *= koef;
    if (cre_collection[attacker]['shadowattack']) l = 0;

    var hera = 0;
    var herd = 0;
    len = unsafeWindow.stage.pole.obj_array.length;
    for (var k1 = 0; k1 < len; k1++) {
        unsafeWindow.k = unsafeWindow.stage.pole.obj_array[k1];

        if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[attacker].owner)) hera = unsafeWindow.k;
        if ((cre_collection[k].hero) && (cre_collection[k].owner == cre_collection[defender].owner)) herd = unsafeWindow.k;
    };
    if ((cre_collection[defender]['pirate']) && ((unsafeWindow.magic[defender]['sea']) || (unsafeWindow.gtype == 125) || (unsafeWindow.gtype == 126) || (unsafeWindow.gtype == 133))) {
        unsafeWindow.PhysicalModifiers *= 0.85;
    };
    if (cre_collection[defender]['deadflesh']) {
        unsafeWindow.PhysicalModifiers *= 0.8;
    };
    if (cre_collection[defender]['immaterial']) {
        unsafeWindow.PhysicalModifiers *= 0.65;
    };
    if ((cre_collection[attacker]['oppressionofweak']) && (cre_collection[defender]['level'] == 1)) {
        unsafeWindow.PhysicalModifiers *= 1.5;
    };
    if ((cre_collection[attacker]['fearofstrong']) && (cre_collection[defender]['level'] == 7)) {
        unsafeWindow.PhysicalModifiers *= 0.5;
    };
    if ((hera > 0) && (unsafeWindow.magic[hera]['bna'])) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[hera]['bna']['effect'] / 100);
        if ((cre_collection[defender]['mechanical']) && (unsafeWindow.magic[hera]['MEC'])) {
            unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['MEC']['effect'] / 100;
        };
        if ((cre_collection[attacker]['mechanical']) && (unsafeWindow.magic[hera]['mch'])) {
            unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[hera]['mch']['effect'] / 100;
        };
    };
    if ((cre_collection[defender]['building']) && (!cre_collection[attacker]['siegewalls'])) {
        unsafeWindow.PhysicalModifiers *= 0.05;
    };
    if ((defender > 0) && (cre_collection[attacker]['cruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
        unsafeWindow.PhysicalModifiers *= 1.15;
    };
    if ((defender > 0) && (cre_collection[attacker]['morecruelty']) && ((cre_collection[defender]['nowhealth'] < cre_collection[defender]['maxhealth']) || (cre_collection[defender]['nownumber'] < cre_collection[defender]['maxnumber']))) {
        unsafeWindow.PhysicalModifiers *= 1.3;
    };
    if ((cre_collection[attacker]['giantkiller']) && (cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 2;
    if ((cre_collection[attacker]['pygmykiller']) && (!cre_collection[defender]['big'])) unsafeWindow.PhysicalModifiers *= 1.33;
    if (cre_collection[attacker]['stormstrike']) unsafeWindow.PhysicalModifiers *= 2;
    if ((cre_collection[attacker]['undeadkiller']) && (cre_collection[defender]['undead'])) unsafeWindow.PhysicalModifiers *= 1.5;
    if ((cre_collection[attacker]['pirate']) && (unsafeWindow.magic[defender]['blb'])) unsafeWindow.PhysicalModifiers *= 1.5;
    if ((!cre_collection[attacker]['hero']) && (unsafeWindow.magic[attacker]['zat'])) {
        unsafeWindow.PhysicalModifiers *= 1.15;
    };
    if ((herd > 0) && (unsafeWindow.magic[herd]['bnd'])) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers / (1 + unsafeWindow.magic[herd]['bnd']['effect'] / 100);
    };
    if ((herd > 0) && (unsafeWindow.magic[herd]['fld'])) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[herd]['fld']['effect'] / 100);
    };
    if ((herd > 0) && (unsafeWindow.magic[herd]['rcd']) && (monster_race[cre_collection[attacker]['id']] == unsafeWindow.magic[herd]['rcd']['effect'])) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.93;
    };
    if (unsafeWindow.magic[attacker]['prp']) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + unsafeWindow.magic[attacker]['prp']['effect'] / 100);
    };
    if (unsafeWindow.magic[defender]['sta']) {
        unsafeWindow.PhysicalModifiers *= 0.5;
    };
    if ((unsafeWindow.magic[attacker]['chd']) && (cre_collection[unsafeWindow.magic[attacker]['chd']['effect']]['nownumber'] > 0) && (unsafeWindow.magic[attacker]['chd']['effect'] != defender)) {
        unsafeWindow.PhysicalModifiers *= 0.55;
    };
    unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.checkmembrane(defender);
    if (!cre_collection[attacker]['hero']) {
        if ((l <= 2) && (cre_collection[attacker]['shooter']) && (!cre_collection[attacker]['nopenalty']) && (!cre_collection[attacker]['warmachine'])) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
        };
        if ((l > 2) && (cre_collection[attacker]['rangepenalty'])) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
        };
        unsafeWindow.rangemod = 1;
        if ((l > 2) && (cre_collection[attacker]['shooter']) && (((cre_collection[attacker]['range'] < Math.sqrt(l)) && (!cre_collection[attacker].shadowattack)) || ((iswalls) && (!cre_collection[attacker]['hero']) && (unsafeWindow.checkwall(x, y, ax, ay))))) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
            unsafeWindow.rangemod = 0.5;
        };
        if ((l > 2) && (cre_collection[attacker]['shooter']) && (iswalls2) && (!cre_collection[attacker]['hero']) && (((!cre_collection[attacker].siegewalls) || (btype == 118)) || (!cre_collection[defender].stone)) && (unsafeWindow.checkwall2(x, y, ax, ay, attacker))) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
            unsafeWindow.rangemod *= 0.5;
        };
    };
    var _PERK_ARCHERY = 11;
    var _PERK_EVASION = 22;
    if ((defender > 0) && (cre_collection[defender]['dodge']) && (((l <= 2) && (!cre_collection[attacker]['ballista']) && (inuse != 'ssh') && (inuse != 'mga') && (inuse != 'dcd') && (inuse != 'chs') && (!cre_collection[attacker]['hero'])) || (inuse == 'brs') || (inuse == 'cpt'))) {
        unsafeWindow.PhysicalModifiers *= 0.5;
    };
    if ((shootok == 1) && (!cre_collection[attacker]['hero']) && (cre_collection[attacker]['shooter'])) {
        if (unsafeWindow.isperk(attacker, _PERK_ARCHERY)) unsafeWindow.PhysicalModifiers *= 1.2;
        if (unsafeWindow.isperk(defender, _PERK_EVASION)) unsafeWindow.PhysicalModifiers *= 0.8;
        if ((!cre_collection[defender]['lshield']) && (unsafeWindow.stage.pole.shieldother(defender))) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
        };
        if ((cre_collection[defender]['lshield']) || (cre_collection[defender]['hollowbones'])) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.5;
        };
        if (cre_collection[defender]['diamondarmor']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.1;
        };
        if (cre_collection[defender]['shielded']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 0.75;
        };
        if (cre_collection[defender]['unprotectedtarget']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * 1.25;
        };
        if (unsafeWindow.magic[defender]['dfm']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[defender]['dfm']['effect'] / 100);
        };
        if (unsafeWindow.magic[attacker]['cnf']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 - unsafeWindow.magic[attacker]['cnf']['effect'] / 100);
        };

        if (hera > 0) {
            if (unsafeWindow.magic[hera]['sat']) {
                unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[hera]['sat']['effect']) / 100;
            };
        };
    };
    if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_BLESS))) {
        unsafeWindow.PhysicalModifiers *= 1.04;
    };
    let o = cre_collection[attacker]['owner'];
    if (unsafeWindow.magic[defender]['mf' + o]) {
        unsafeWindow.PhysicalModifiers *= 1 + unsafeWindow.magic[defender]['mf' + o]['effect'] / 100;
    };
    if ((!cre_collection[attacker]['hero']) && (unsafeWindow.isperk(attacker, _PERK_FERVOR))) {
        unsafeWindow.PhysicalModifiers *= 1.03;
    };
    if (hera > 0) {
        var h = hera;
        if ((unsafeWindow.magic[h]['nut']) && ((plid2 == -2) || (ohotnik_set_neutral()))) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['nut']['effect']) / 100;
        };
        if ((unsafeWindow.magic[h]['mle']) && ((cre_collection[attacker].shooter && shootok==0)||(cre_collection[attacker].shooter!= 1) || cre_collection[attacker].shots==0)) {
          unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + unsafeWindow.magic[h]['mle']['effect']) / 100;
        };
        if (unsafeWindow.magic[attacker]['fbd']) {
            unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 + Math.floor(unsafeWindow.magic[attacker]['fbd']['effect'] / 10)) / 100;
        };
    };
    unsafeWindow.monatt = cre_collection[attacker]['attack'] + cre_collection[attacker]['attackaddon'] + cre_collection[attacker]['rageattack'];
    if ((defender > 0) && (cre_collection[attacker]['giantslayer']) && (cre_collection[defender]['big'])) unsafeWindow.monatt += 4;
    if ((!cre_collection[attacker]['undead']) && (!cre_collection[attacker]['hero']) && (!cre_collection[attacker]['perseverance'])) {
        unsafeWindow.frig2 = false;
        unsafeWindow.i = attacker;
        var bigx = cre_collection[i]['big'];
        var bigy = cre_collection[i]['big'];
        if (cre_collection[i]['bigx']) bigx = 1;
        if (cre_collection[i]['bigy']) bigy = 1;
        unsafeWindow.xd = cre_collection[i]['x'];
        unsafeWindow.yd = cre_collection[i]['y'];
        for (var xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
            for (var yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
                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)) {
                    unsafeWindow.monatt -= 4;
                    unsafeWindow.frig2 = true;
                };
            };
        };
    };

    if ((unsafeWindow.magic[attacker]['bsr']) || (unsafeWindow.magic[attacker]['rof'])) {
        unsafeWindow.monatt += Math.floor((cre_collection[attacker]['defence'] + cre_collection[attacker]['defenceaddon'] + cre_collection[attacker]['ragedefence']) * cre_collection[attacker]['defencemodifier']);
    };
    if (herd > 0) {
        h = herd;
        if ((unsafeWindow.magic[h]['mld']) && ((cre_collection[attacker].shooter && shootok==0)||(cre_collection[attacker].shooter!= 1) || cre_collection[attacker].shots==0)) {
          unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['mld']['effect']) / 100;
        };
        if ((unsafeWindow.magic[h]['_ia']) && (!cre_collection[attacker]['perseverance'])) {
            unsafeWindow.monatt *= (1 - unsafeWindow.magic[h]['_ia']['effect'] / 100);
        };
        if ((!cre_collection[attacker]['hero']) && (cre_collection[attacker].shooter)&& (cre_collection[attacker].shots!=0) && (unsafeWindow.magic[h]['msk']) &&  shootok == 1) {
          unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (100 - unsafeWindow.magic[h]['msk']['effect']) / 100;
        };
    };
    unsafeWindow.defadd = 0;
    if (cre_collection[defender]['agility']) {
        if (!unsafeWindow.magic[defender]['agl']) unsafeWindow.defadd = cre_collection[defender]['speed'] * 2;
    };
    if ((cre_collection[defender]['spirit']) && (!unsafeWindow.magic[defender]['spi'])) {
        unsafeWindow.PhysicalModifiers *= 0.5;
    };
    if ((cre_collection[attacker]['rageagainsttheliving']) && (cre_collection[defender]['alive'])) {
        unsafeWindow.PhysicalModifiers *= 1.3;
    };
    if ((cre_collection[defender]['defensivestance']) && (!unsafeWindow.magic[defender]['mvd'])) {
        unsafeWindow.defadd += 5;
    };
    if ((!cre_collection[defender]['undead']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor'])) {
        unsafeWindow.frig2 = false;
        unsafeWindow.i = defender;
        bigx = cre_collection[i]['big'];
        bigy = cre_collection[i]['big'];
        if (cre_collection[i]['bigx']) bigx = 1;
        if (cre_collection[i]['bigy']) bigy = 1;
        unsafeWindow.xd = cre_collection[i]['x'];
        unsafeWindow.yd = cre_collection[i]['y'];
        for (let xz = unsafeWindow.xd - 1; xz <= unsafeWindow.xd + 1 + bigx; xz++) {
            for (let yz = unsafeWindow.yd - 1; yz <= unsafeWindow.yd + 1 + bigy; yz++) {
                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)) {
                    unsafeWindow.defadd -= 4;
                    unsafeWindow.frig2 = true;
                };
            };
        };
    };
    if ((attacker > 0) && (cre_collection[defender]['giantslayer']) && (cre_collection[attacker]['big'])) unsafeWindow.defadd += 4;
    unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + unsafeWindow.defadd + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
    if (unsafeWindow.magic[defender]['bsr']) {
        unsafeWindow.mondef = 0;
    };

    if ((cre_collection[attacker]['preciseshot']) && (l > 2) && (l <= 9) && (unsafeWindow.rangemod >= 1)) {
        unsafeWindow.mondef = 0;
    };
    if ((cre_collection[attacker]['ignoredefence'])) {
        unsafeWindow.mondef *= (1 - cre_collection[attacker]['ignoredefence'] / 100);
    };
    if (cre_collection[attacker]['crushingleadership']) {
        var morale_delta = unsafeWindow.stage.pole.getmorale(attacker) - unsafeWindow.stage.pole.getmorale(defender);
        if (morale_delta > 0) {
            unsafeWindow.mondef *= Math.max(0, 1 - morale_delta / 10);
        };
    };
    if (cre_collection[attacker]['sacredweapon']) {
        var dark_count = get_dark_count(defender);
        if (dark_count > 0) {
            unsafeWindow.mondef *= Math.max(0, 1 - 0.15 * dark_count);
        };
    };
    if (unsafeWindow.isperk(attacker, _PERK_PIERCING_LUCK)) {
        unsafeWindow.mondef *= 1 - Math.max(0, 0.025 * (cre_collection[attacker]['luck'] + cre_collection[attacker]['luckaddon']));
    };
    if ((cre_collection[defender]['ignoreattack'])) {
        unsafeWindow.monatt *= (1 - cre_collection[defender]['ignoreattack'] / 100);
    };
    if ((cre_collection[attacker]['ridercharge']) && (movelen > 0)) {
        unsafeWindow.mondef = unsafeWindow.mondef * (5 - movelen) / 5;
    };
    if ((cre_collection[attacker]['forcearrow']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
        unsafeWindow.mondef *= 0.8;
    };
    if ((cre_collection[attacker]['armorpiercing']) && (!cre_collection[defender]['armoured']) && (!cre_collection[defender]['organicarmor']) && (l > 2)) {
        unsafeWindow.mondef *= 0.5;
    };
    if ((cre_collection[attacker]['jousting']) && (movelen > 0)) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.05 * movelen);
    };
    if (((cre_collection[attacker]['blindingcharge']) || (cre_collection[attacker]['charge'])) && (movelen > 0)) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * (1 + 0.1 * movelen);
    };
    if ((cre_collection[defender]['shieldwall']) && (movelen > 0)) {
        unsafeWindow.PhysicalModifiers = unsafeWindow.PhysicalModifiers * Math.max(0.1, 1 - 0.1 * movelen);
    };
    if ((unsafeWindow.magic[defender]['enc']) && (unsafeWindow.magic[defender]['enc']['effect'] == 1)) {
        unsafeWindow.PhysicalModifiers *= 0.5;
    };
    if ((cre_collection[attacker]['safeposition']) && (movelen == 0)) {
        unsafeWindow.PhysicalModifiers *= 1.5;
    };
    if ((cre_collection[attacker]['agilesteed']) && (movelen > 0)) {
        unsafeWindow.PhysicalModifiers *= 1 - 0.05 * movelen;
    };
    if (unsafeWindow.mondef < 0) {
        unsafeWindow.mondef = 0;
    };

    unsafeWindow.air = 0;
    unsafeWindow.fire = 0;
    unsafeWindow.water = 0;
    unsafeWindow.earth = 0;
    if ((hera > 0) && (!cre_collection[attacker]['taran'])) {
        h = hera;
        if (unsafeWindow.magic[h]['_id']) {
            unsafeWindow.mondef *= (1 - unsafeWindow.magic[h]['_id']['effect'] / 100);
        };
        if (unsafeWindow.magic[h]['_aa']) {
            unsafeWindow.air = unsafeWindow.magic[h]['_aa']['effect'] / 100;
        };
        if (unsafeWindow.magic[h]['_af']) {
            unsafeWindow.fire = unsafeWindow.magic[h]['_af']['effect'] / 100;
        };
        if (unsafeWindow.magic[h]['_aw']) {
            unsafeWindow.water = unsafeWindow.magic[h]['_aw']['effect'] / 100;
        };
        if (unsafeWindow.magic[h]['_ae']) {
            unsafeWindow.earth = unsafeWindow.magic[h]['_ae']['effect'] / 100;
        };
    };
    if ((cre_collection[defender]['armoured']) || (cre_collection[defender]['organicarmor'])) {
        unsafeWindow.mondef = Math.round((cre_collection[defender]['defence'] + cre_collection[defender]['defenceaddon'] + cre_collection[defender]['ragedefence']) * cre_collection[defender]['defencemodifier']);
    };
    if (unsafeWindow.monatt < 0) {
        unsafeWindow.monatt = 0;
    };
    if (unsafeWindow.monatt > unsafeWindow.mondef) {
        unsafeWindow.AttackDefenseModifier = 1 + (unsafeWindow.monatt - unsafeWindow.mondef) * 0.05;
    } else {
        unsafeWindow.AttackDefenseModifier = 1 / (1 + (unsafeWindow.mondef - unsafeWindow.monatt) * 0.05);
    };
    if (cre_collection[attacker]['hero']) {
        unsafeWindow.AttackDefenseModifier = 1;
    };
    var _PERK_ATTACK1 = 8;
    var _PERK_ATTACK2 = 9;
    var _PERK_ATTACK3 = 10;
    var _PERK_DEFENSE1 = 19;
    var _PERK_DEFENSE2 = 20;
    var _PERK_DEFENSE3 = 21;

    if ((!cre_collection[attacker]['hero'])&& ((cre_collection[attacker].shooter && shootok == 0)||(cre_collection[attacker].shooter!= 1))) {
        if (unsafeWindow.isperk(attacker, _PERK_ATTACK3)) {
            unsafeWindow.PhysicalModifiers *= 1.3;
        } else {
            if (unsafeWindow.isperk(attacker, _PERK_ATTACK2)) {
                unsafeWindow.PhysicalModifiers *= 1.2;
            } else
                if (unsafeWindow.isperk(attacker, _PERK_ATTACK1)) unsafeWindow.PhysicalModifiers *= 1.1;
        };
        if (unsafeWindow.isperk(defender, _PERK_DEFENSE3)) {
            unsafeWindow.PhysicalModifiers *= 0.7;
        } else {
            if (unsafeWindow.isperk(defender, _PERK_DEFENSE2)) {
                unsafeWindow.PhysicalModifiers *= 0.8;
            } else {
                if (unsafeWindow.isperk(defender, _PERK_DEFENSE1)) unsafeWindow.PhysicalModifiers *= 0.9;
            };
        };
    };
    if ((cre_collection[attacker]['siegewalls']) && (cre_collection[defender]['stone'])) {
        unsafeWindow.PhysicalModifiers *= 10;
    };
    var _PERK_COLD_STEEL = 14;
    var _PERK_FIERY_WRATH = 101;
    var _PERK_HELLFIRE_AURA = 123;
    var _PERK_RETRIBUTION = 16;

    if (unsafeWindow.isperk(attacker, _PERK_COLD_STEEL)) unsafeWindow.water = 1 - (1 - unsafeWindow.water) * (0.9);
    if (unsafeWindow.isperk(attacker, _PERK_FIERY_WRATH)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.85);
    if (unsafeWindow.isperk(attacker, _PERK_HELLFIRE_AURA)) unsafeWindow.fire = 1 - (1 - unsafeWindow.fire) * (0.95);

    if (unsafeWindow.magic[attacker]['cre']) {
        unsafeWindow.air = 1 - (1 - unsafeWindow.air) * (1 - unsafeWindow.magic[attacker]['cre']['effect'] / 100);
    };

    if (unsafeWindow.isperk(attacker, _PERK_RETRIBUTION)) unsafeWindow.PhysicalModifiers *= (1 + Math.min(Math.max(unsafeWindow.stage.pole.getmorale(attacker, x, y), 0), 5) / 20);
    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;
    unsafeWindow.PhysicalModifiers *= unsafeWindow.stage.pole.magicmod(attacker, defender, unsafeWindow.fire, unsafeWindow.air, unsafeWindow.water, unsafeWindow.earth, 0.1);
    if ((cre_collection[attacker]['bloodfrenzy']) && (unsafeWindow.magic[defender]['fd1'])) {
        unsafeWindow.PhysicalModifiers *= 1.3;
    };
    unsafeWindow.UmelkaModifiers = 1;

    if ((umelka[cre_collection[attacker]['owner']][0] > 0) && (umelka[cre_collection[defender]['owner']][0] > 0)) {
        unsafeWindow.k = umelka[cre_collection[attacker]['owner']][0];
        if ((unsafeWindow.k > 0) && (unsafeWindow.k < 11)) {
            let j = umelka[cre_collection[defender]['owner']][k];
            unsafeWindow.UmelkaModifiers = 1 - j * 0.03;
        };
    };
    unsafeWindow.NumCreatures = cre_collection[attacker]['nownumber'];
    let tsc = 0;

    bigx = cre_collection[defender]['big'];
    bigy = cre_collection[defender]['big'];
    if (cre_collection[defender]['bigx']) bigx = 1;
    if (cre_collection[defender]['bigy']) bigy = 1;
    for (var xs = cre_collection[defender]['x'] - 1; xs <= cre_collection[defender]['x'] + 1 + bigx; xs++) {
        for (var ys = cre_collection[defender]['y'] - 1; ys <= cre_collection[defender]['y'] + 1 + bigy; ys++) {
            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'])) {
                tsc++;
            };
        };
    };


    unsafeWindow.PhysicalModifiers /= (tsc + 1);

    var minmag = 0;
    var maxmag = 0;
    if ((inuse == 'lep') && (cre_collection[attacker]['crashingleap'])) {
        unsafeWindow.Totalmagicdamage = 0;
        cre_collection[defender]['attacked'] = 1;
        unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 4, 'cold', '', 0, 0, 0);
        minmag = unsafeWindow.Totalmagicdamage;
        unsafeWindow.Totalmagicdamage = 0;
        cre_collection[defender]['attacked'] = 1;
        unsafeWindow.stage.pole.attackmagic(attacker, defender, cre_collection[attacker]['nownumber'] * 6, 'cold', '', 0, 0, 0);
        maxmag = unsafeWindow.Totalmagicdamage;
    };

    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'];
    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'];
    h = hera;
    if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['BLS']) && (unsafeWindow.magic[h]['BLS']['effect'] > 0)) unsafeWindow.mindam = unsafeWindow.maxdam;
    if ((h > 0) && (unsafeWindow.magic[h]) && (unsafeWindow.magic[h]['CRS']) && (unsafeWindow.magic[h]['CRS']['effect'] > 0)) unsafeWindow.maxdam = unsafeWindow.mindam;
    if ((cre_collection[attacker]['taran']) && (cre_collection[defender]['stone'])) {
        h = hera;
        unsafeWindow.mindam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 200 * cre_collection[attacker]['mindam']);
        unsafeWindow.maxdam = Math.floor(Math.pow(cre_collection[h]['maxhealth'], 0.5) * 400 * cre_collection[attacker]['maxdam']);
    };
    if (cre_collection[attacker]['accuracy']) unsafeWindow.mindam = unsafeWindow.maxdam;
    unsafeWindow.BaseDamage = unsafeWindow.mindam;
    unsafeWindow.PhysicalDamage = unsafeWindow.NumCreatures * unsafeWindow.BaseDamage * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + minmag;
    unsafeWindow.PhysicalDamage2 = unsafeWindow.NumCreatures * unsafeWindow.maxdam * unsafeWindow.AttackDefenseModifier * unsafeWindow.PhysicalModifiers * unsafeWindow.UmelkaModifiers + maxmag;
    if ((cre_collection[attacker]['deathstrike']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
        if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage) {
            unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage % cre_collection[defender]['maxhealth'];
        };
        if ((cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'] > unsafeWindow.PhysicalDamage2) {
            unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'] - unsafeWindow.PhysicalDamage2 % cre_collection[defender]['maxhealth'];
        };
    };

    if (cre_collection[attacker]['bladeofslaughter']) {
        unsafeWindow.PhysicalDamage += Math.min(500, cre_collection[defender]['nownumber'] * 2);
        unsafeWindow.PhysicalDamage2 += Math.min(500, cre_collection[defender]['nownumber'] * 2);
    };
    if (unsafeWindow.magic[attacker]['brk']) {
        unsafeWindow.PhysicalDamage *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
        unsafeWindow.PhysicalDamage2 *= (1 + unsafeWindow.magic[attacker]['brk']['effect'] * 0.03);
    };
    if (unsafeWindow.PhysicalDamage < 1) {
        unsafeWindow.PhysicalDamage = 1;
    };
    if (unsafeWindow.PhysicalDamage2 < 1) {
        unsafeWindow.PhysicalDamage2 = 1;
    };
    if ((cre_collection[attacker]['magicattack']) && (unsafeWindow.l > 2) && (unsafeWindow.stage.pole.issomething(defender, 'dampenmagic'))) unsafeWindow.PhysicalDamage = 0;
    if (unsafeWindow.magic[defender]['rag']) {
        unsafeWindow.PhysicalDamage = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage);
        unsafeWindow.PhysicalDamage2 = unsafeWindow.stage.pole.ragedamage(defender, unsafeWindow.PhysicalDamage2);
    };
    if ((cre_collection[attacker]['vorpalsword']) && (cre_collection[defender]['maxhealth'] < 400) && (!cre_collection[defender]['stone'])) {
        unsafeWindow.PhysicalDamage += cre_collection[defender]['maxhealth'];
        unsafeWindow.PhysicalDamage2 += cre_collection[defender]['maxhealth'];
    };

    unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage);
    unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2);
    if (cre_collection[defender]['pleasureinpain']) {
        unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.9);
        unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.9);
    };
    if (cre_collection[defender]['raptureinagony']) {
        unsafeWindow.PhysicalDamage = Math.round(unsafeWindow.PhysicalDamage * 0.8);
        unsafeWindow.PhysicalDamage2 = Math.round(unsafeWindow.PhysicalDamage2 * 0.8);
    };
    var totalh = (cre_collection[defender]['nownumber'] - 1) * cre_collection[defender]['maxhealth'] + cre_collection[defender]['nowhealth'];
    unsafeWindow.Uronkills = Math.floor(Math.min(unsafeWindow.PhysicalDamage, totalh) / cre_collection[defender]['maxhealth']);
    unsafeWindow.Uronkills2 = Math.floor(Math.min(unsafeWindow.PhysicalDamage2, totalh) / cre_collection[defender]['maxhealth']);
    var nowhealth = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage, totalh) - unsafeWindow.Uronkills * cre_collection[defender]['maxhealth']);
    var nowhealth2 = cre_collection[defender]['nowhealth'] - (Math.min(unsafeWindow.PhysicalDamage2, totalh) - unsafeWindow.Uronkills2 * cre_collection[defender]['maxhealth']);
    if (nowhealth <= 0) unsafeWindow.Uronkills++;
    if (nowhealth2 <= 0) unsafeWindow.Uronkills2++;
    unsafeWindow.tUronkills += unsafeWindow.Uronkills;
    unsafeWindow.tUronkills2 += unsafeWindow.Uronkills2;
    unsafeWindow.tPhysicalDamage += unsafeWindow.PhysicalDamage;
    unsafeWindow.tPhysicalDamage2 += unsafeWindow.PhysicalDamage2;
    return movelen
}
function get_dmg_info(attacker_obj_index, defender_obj_index){
    let cre_collection = unsafeWindow.stage.pole.obj
    let attacker = cre_collection[attacker_obj_index]
    let defender = cre_collection[defender_obj_index]
    let dmg_dict = attackmonster(attacker_obj_index, attacker.x, attacker.y, defender.x, defender.y, defender_obj_index, GM_getValue("cre_distance"));
    let min_damage = unsafeWindow.PhysicalDamage
    let max_damage = unsafeWindow.PhysicalDamage2
    let min_killed, max_killed;
    if (min_damage%defender.maxhealth>defender.nowhealth) min_killed = Math.floor(min_damage/defender.maxhealth) + 1
    else min_killed = Math.floor(min_damage/defender.maxhealth)
    if (max_damage%defender.maxhealth>defender.nowhealth) max_killed = Math.floor(max_damage/defender.maxhealth) + 1
    else max_killed = Math.floor(max_damage/defender.maxhealth)
    return {min: min_damage, max: max_damage, min_killed: min_killed, max_killed: max_killed}
}

let defender_obj_id = 0
let selected_id = 0
function refresh(){
    isOpen = true
    let cre_collection = unsafeWindow.stage.pole.obj
    battleHelper_display(battleHelper_on)
    if (cre_distance_on) {
        cre_distance_div.style.display = "inline";
        cre_distance_div.innerHTML = `<span>Выбранное расстояние: ${GM_getValue('cre_distance')}</span><br>`
    }
    set_Display([select, side_button, collapse_button, document.querySelector("#chosen_cre_heading"), dmg_list_container, individual_calc], "inline")

    refresh_button.innerHTML = "Обновить"
    let cre_list = Object.values(cre_collection);
    cre_list.sort(function(a, b) {
        return a.obj_index - b.obj_index;
    });
    dmg_list_container.innerHTML = "";
    [...select.children].forEach(child=>child.remove())
    let found_defender = false
    cre_list.forEach(defender => {
        if (![0,-1].includes(defender.nownumber) && defender.nametxt!="" && defender.side == chosen.side && defender.hero == undefined){
            let option_id = `cre_no${cre_list.indexOf(defender)}`
            select.insertAdjacentHTML("beforeend", `<option id = "${option_id}" value = "${defender.obj_index}">${defender.nametxt} [${defender.nownumber}] </option>`)
            if (!found_defender) {
                if (`${defender.obj_index}` == chosen.creature) found_defender = true
                defender_obj_id = defender.obj_index
                selected_id = [...select.children].indexOf(select.lastChild)
            }
        }
    })
    dmg_list_container.insertAdjacentHTML("beforeend", `<div id = "chosen_cre_heading" style="display:inline;">
  <span>Урон по </span><span style="color:#ffffff; font-size: 110%; font-weight: bold;">${cre_list[defender_obj_id-1].nametxt} [${cre_list[defender_obj_id-1].nownumber}] :</span>
</div>`)
    cre_list.forEach(attacker => {
        if (attacker.side == -chosen.side && attacker.nownumber != 0 && attacker.nametxt != "") {
            let dmg = get_dmg_info(attacker.obj_index, defender_obj_id)
            let practical_overall_hp;
            if (cre_list[defender_obj_id-1].attack>attacker.defence){
                practical_overall_hp = attacker.maxhealth*attacker.nownumber/(1+0.05*Math.abs(cre_list[defender_obj_id-1].attack-attacker.defence))
            }
            else {
                practical_overall_hp = attacker.maxhealth*attacker.nownumber*(1+0.05*Math.abs(cre_list[defender_obj_id-1].attack-attacker.defence))
            }
            let row_id = `row_no${cre_list.indexOf(attacker)}`
            let koef_string = `(коэф. урона <b>${(  ((dmg.max + dmg.min) / 2) / practical_overall_hp  ).toFixed(2)}</b>)`
            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>`)
        }
    })
    select.options.item(selected_id).selected = true
}