Greasy Fork is available in English.

battle_damage_tooltip

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

Fra og med 13.05.2023. Se den nyeste version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         battle_damage_tooltip
// @namespace    http://tampermonkey.net/
// @version      1.3.6
// @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");
let atLaunch = true
outer_chat.insertAdjacentHTML("beforeend", `
<div id="cre_distance_div" style="display: none"></div>
<div id="individual_calc"></div>
<div id="dmg_list_container"></div>
<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>`
outer_chat.insertAdjacentHTML('afterbegin', `<div id = "battlehelper_div"></div>`)
let battlehelper_div = document.querySelector('#battlehelper_div');

// ========= 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 getCurrentBattleSpeed(){
    for(let i = 1; i<=3; i++){
        let div = document.querySelector(`#speed${i}_button`)
        if (div.style.display === 'none') continue
        if (i === 1) return 2
        else if (i === 3) return 1
        else return 4
    }
}
function setBattleSpeed(value){
    if (value === 0) return value
    else if (value < 1) {
        unsafeWindow.timer_interval = Math.abs(value) * 20;
        return value
    }
    unsafeWindow.animspeed_def = unsafeWindow.animspeed = value
    unsafeWindow.animspeed_init = unsafeWindow.animspeed > 4 ? 0.5 : 2;
    unsafeWindow.timer_interval = Math.abs(value-20)
    !unsafeWindow.timer_interval && unsafeWindow.timer_interval++;
    return 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.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') return
        for (const addedNode of mutation.addedNodes) {
            if (!(addedNode.classList && addedNode.classList.contains('cont') || ["B", "BR"].includes(addedNode.tagName))) continue
            wrap_battlehelper();
            battlehelper_div.style.display = battleHelper_on ? "inline" : "none";
        }
    }
});

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")
    battlehelper_div = document.querySelector("#battlehelper_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)
let animation_speed_on = get_GM_value_if_exists("animation_speed_on", false)
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>
<div class="info_row">
    <label class="checkbox_container">Скорость анимации <span class="tooltip">? <span class="tooltiptext"> Скорость боевых анимаций. <br> Выбирать расстояние стрелочками в текстовом поле снизу или если зажать кнопку Alt и нажимать на стрелки клавиатуры.<br> Включить/выключить анимацию [Alt + P (русская З)].<br> Анимацию можно как ускорить, так и замедлить.<br>Верхний потолок у скорости 20, нижнего нету.<br> Негативный показатель означает скорость ниже возможной гвдшной. </span>
      </span>
      <input type="checkbox" checked="true" id="animation_speed_on">
      <span class="checkbox_checkmark"></span>
    </label>
    <input type="number" style="width: 5%; margin: 2px 2px 2px 80px" id="anim_speed" onkeydown="return false;" >
  </div>

`
settings_panel.insertAdjacentHTML("beforeend", new_settings)

let settings_interval = setInterval(()=>{
    if (Object.keys(unsafeWindow.stage.pole.obj).length !== 0){
        document.querySelector("#coeff_on").checked = coeff_on
        document.querySelector("#battleHelper_on").checked = battleHelper_on
        document.querySelector("#cre_distance_on").checked = cre_distance_on
        document.querySelector("#animation_speed_on").checked = animation_speed_on
        let spd = get_GM_value_if_exists("anim_speed", getCurrentBattleSpeed())
        document.querySelector("#anim_speed").value = spd
        if (GM_getValue("animation_speed_on")) setBattleSpeed(spd)
        clearInterval(settings_interval)
    }
},300)
const distance_counter = document.getElementById("cre_distance");
const anim_speed_counter = document.querySelector("#anim_speed")


// =========  Event Listeners ============
document.body.addEventListener('input', function(event){
    switch (event.target.id){
        case "cre_distance":
            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>`
            break;
        case "anim_speed":
            if (anim_speed_counter.value > 20){
                anim_speed_counter.value = 20
                return
            }
            GM_setValue('anim_speed', anim_speed_counter.value)
            if (!animation_speed_on) return
            setBattleSpeed(anim_speed_counter.value)
            break;
    }
});
const anim_speed_input = document.querySelector('#anim_speed')
document.addEventListener('keydown', event => {
    if (!event.altKey) return
    if (["P", "p", "з", "З"].includes(event.key)) {
        animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
        document.querySelector("#animation_speed_on").checked = animation_speed_on
        if (animation_speed_on){
            GM_setValue('anim_speed', anim_speed_counter.value)
            setBattleSpeed(anim_speed_counter.value);
        }
        else {
            setBattleSpeed(getCurrentBattleSpeed());
        }
    }
    if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
        event.preventDefault();
        const increment = event.key === 'ArrowUp' ? 1 : -1;
        anim_speed_input.value = parseInt(anim_speed_input.value) + increment;
        anim_speed_input.dispatchEvent(new Event('input', { bubbles: true }));
    }
});
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_div.style.display = battleHelper_on ? "inline" : "none";
            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;
        case "animation_speed_on":
            animation_speed_on = GM_toggle_boolean("animation_speed_on", GM_getValue("animation_speed_on"))
            if (animation_speed_on){
                GM_setValue('anim_speed', anim_speed_counter.value)
                setBattleSpeed(anim_speed_counter.value);
            }
            else {
                setBattleSpeed(getCurrentBattleSpeed());
            }
            break;
    }
});
document.body.addEventListener('click', function(event) {
    if (event.target.parentElement && /speed(.)_button/.test(event.target.parentElement.id)) {
        setBattleSpeed(getCurrentBattleSpeed());
        document.querySelector("#animation_speed_on").checked = false
        GM_setValue('animation_speed_on', false)
    }
    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
            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);
            break;
    }
});
// Урон одного стека по другому по выбору нажатием кнопки E
window.addEventListener("keyup", event => {
    if (event.key === 'Escape'){
    document.querySelector("#win_Settings").style.display = document.querySelector("#win_Settings").style.display ? '' : 'none';
    }
    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")
            }
        }
    }
});
// -----------------------------------

// =========  battleHelper ============
function wrap_battlehelper(){
    for (const child of battlehelper_div.children) {
        if (child.className === "cont") return
    }
    readjust_elements();
    let el_transfer = [];
    [...outer_chat.children].forEach(child=>{
        if (["B","BR"].includes(child.tagName) || child.className == "cont"){
            el_transfer.push(child)
        }
    });
    for (const el of el_transfer) battlehelper_div.appendChild(el);
    const first_icons = battlehelper_div.querySelectorAll('br + div.cont');
    let teams_text = [...outer_chat.childNodes].filter(node => (node.nodeType === node.TEXT_NODE && /Команда №(\d)/.test(node.textContent.trim())));
    let i = 0
    for (const img_div of first_icons){
        img_div.previousSibling.insertAdjacentHTML('beforebegin', teams_text[i].textContent);
        i++;
    }
    for (const el of teams_text) el.remove()
    let title_arr = [...battlehelper_div.children].filter(child => child.textContent === "Стартовый бонус АТБ")
    if (battlehelper_div.children.length === 2 && title_arr.length === 1) {
        battlehelper_div.innerHTML = " "
    }
}
observer.observe(outer_chat, { childList: true });
setTimeout(function() {
    observer.disconnect();
}, 30000);

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




// Родная функция гвд с поправками на переменную 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
    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
}